<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Fullstack Digital - Medium]]></title>
        <description><![CDATA[Digitally exploring thoughts around brand, web, marketing and tech. The official blog for www.fullstackdigital.com - Medium]]></description>
        <link>https://blog.fullstackdigital.com?source=rss----9b1e3bc24b6e---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Fullstack Digital - Medium</title>
            <link>https://blog.fullstackdigital.com?source=rss----9b1e3bc24b6e---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Tue, 07 Apr 2026 10:25:06 GMT</lastBuildDate>
        <atom:link href="https://blog.fullstackdigital.com/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[How to cache-bust and concatenate JS and SASS files with Hugo in 2018]]></title>
            <link>https://blog.fullstackdigital.com/how-to-cache-bust-and-concatenate-js-and-sass-files-with-hugo-in-2018-9266fd3c411e?source=rss----9b1e3bc24b6e---4</link>
            <guid isPermaLink="false">https://medium.com/p/9266fd3c411e</guid>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[cms]]></category>
            <category><![CDATA[static-site]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[hugo]]></category>
            <dc:creator><![CDATA[Ben Bozzay]]></dc:creator>
            <pubDate>Mon, 11 Mar 2019 15:32:06 GMT</pubDate>
            <atom:updated>2020-09-04T17:25:29.047Z</atom:updated>
            <content:encoded><![CDATA[<p><a href="https://twitter.com/BenBozzay"><em>Follow me on Twitter</em></a><em> for more Hugo, front-end development, and digital marketing tutorials.</em></p><p><a href="https://gohugo.io/">Hugo</a> released <a href="https://github.com/gohugoio/hugo/releases/tag/v0.43">version 0.43</a> adding built-in asset post-processing. As our team wraps up development of a free page-builder theme that utilizes Forestry.io, Netlify, and Hugo, we were thrilled to replace our asset processing tasks with Hugo’s pipeline.</p><p>The addition of built-in asset pipeline support allowed us to simplify our build process and reduce potential conflicts caused when deploying with Netlify. Here’s how we replaced our Gulp tasks with Hugo’s new asset pipeline to add <strong>SASS support</strong> and to <strong>concatenate</strong>, <strong>minify</strong>, and <strong>fingerprint</strong> JS and CSS.</p><h3>Built-in SASS support</h3><p>Since Hugo previously did not provide built-in support for SCSS, Gulp was commonly used for SCSS generation. This wasn’t ideal for us because the build and deploy process with Netlify would sometimes encounter issues. As a result, we would just commit processed assets instead of using Netlify to build assets.</p><h4>Using SCSS with Hugo in 2018</h4><p><a href="https://sass-lang.com/guide">Sass</a> provides many benefits that simplify theme development. For example, it enables the use of variables for CSS values.</p><pre>$font-stack:    Helvetica<strong>,</strong> sans-serif;<br>$primary-color: #333;<br><br>body {<br>  <strong>font</strong>: 100% $font-stack;<br>  <strong>color</strong>: $primary-color;<br>}</pre><p>This is especially useful for theme development when user’s are able to define these variables themselves and quickly change the style of a theme.</p><p>Partial Sass files allow you to better organize your CSS. These files, which use a leading underscore, are then imported and combined into a single file.</p><p><strong><em>Note: you must use the extended version of 0.43 for Sass support.</em></strong></p><ol><li>In your <strong>theme folder</strong> or the <strong>top-level of your project </strong>add an assets folder to store your SCSS:</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/426/1*MXUXIaOQ9jpmxirp6PtNHw.png" /></figure><p>By default, resource objects live in the /assets/ directory (you will most likely need to add this folder).</p><p>2. Add a main.scss file to your scss directory:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/381/1*_Jr1s4fDMNVDnr5R3KDFcw.png" /></figure><p>3. In main.scss, import your partial SCSS:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/522/1*7vyjjHbpe_2pEaq6EcaUvQ.png" /></figure><p>If you define variables that are used in other partial files, you must import that partial file first. For example, we use a file called _variables.scss to define fonts and colors.</p><p>4. Generate the resource:</p><pre>{{ $styles := resources.Get “scss/main.scss” | toCSS }}</pre><p>You can learn more about the resource functions within <a href="https://github.com/gohugoio/hugo/issues/4854">#4854</a>. This seems to provide more context then the release page.</p><p>For example, resources.Get creates a new resource object based on a path to a file within the /assets directory.</p><p>In the code snippet above, resources.Get generates a file in the resources directory:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/423/1*BggSJbrPKru2qPMp0bNSXQ.png" /><figcaption>In this particular example fingerprinting is enabled, which is why this file has a hash</figcaption></figure><p>5. Reference the newly generated SCSS file:</p><pre>{{ $styles := resources.Get “scss/main.scss” | toCSS }}</pre><pre>&lt;link rel=”stylesheet” href=”{{ $styles.Permalink }}” media=”screen”&gt;</pre><p>Appending .Permlink to the styles variable generates the URL needed to reference the scss file in our resources directory.</p><h3>Cache-busting using fingerprinting</h3><p>Cache busting allows you to force the browser to re-download files that are usually cached. CDN’s like Cloudflare and a user’s browser will cache certain resources like stylesheets to reduce page load time. This means that a user might not see newly committed stylesheet updates unless the browser cache is cleared.</p><p>If you are using Cloudflare, you’d need to enable development mode and clear the Cloudflare cache before committing your stylesheet update so that user’s browsers do not cache Cloudflares cached version of your stylesheet :).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/533/1*ACo2X7LuQqNzvT4Q_cMbqg.png" /></figure><p><strong>Fingerprinting</strong> generates a unique hash when you recompile your stylesheet. This means that the file name changes every time you commit your stylesheet. Cloudflare and the user’s browser will re-download the asset since the name changed.</p><p>We can also <a href="https://en.wikipedia.org/wiki/Minification_(programming)">minify</a> our stylesheet to reduce the file size. Resources functions like toCSS, minify, and fingerprint can be chained!</p><p>6. Add fingerprinting and minification to your stylesheet:</p><pre>{{ $styles := resources.Get “scss/main.scss” | toCSS | minify | fingerprint }}</pre><p>7. Add .Data.Integrity to fingerprinted resources.</p><pre>&lt;link rel=”stylesheet” href=”{{ $styles.Permalink }}” integrity=&quot;{{ $styles.Data.Integrity&quot; media=”screen”&gt;</pre><p>According to this <a href="https://github.com/gohugoio/hugo/issues/4854">issue</a>, Data.Integrity <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity">should be added to fingerprinted resources</a> to provide verification that changed files are not malicious.</p><h3>Overwriting your theme’s SCSS</h3><p>If you have an assets folder in the top-level of your project and an assets folder in your theme directory, Hugo will prioritize the top-level directory over the theme directory. This means that you can overwrite theme files without modifying the theme directory. This is similar to how Wordpress child themes work.</p><pre>assets<br>  └── scss<br>  |   └── _accordian.scss<br>themes<br>  └── pancakes<br>  |   └── assets<br>          └── scss<br>              └── _accordian.scss</pre><p>In our particular scenario, we plan to release a free, open source builder theme as a <strong>git submodule</strong>. This will allow us to push theme updates. However, we can provide user’s with guidance on how to safely overwrite theme layouts and scss files without conflicting with theme updates.</p><h3>Combining JS files</h3><p>Hugo 0.43 added resources.Concat, which means that we can combine JS files without using a bundler.</p><p>Directory priority is still the same:</p><pre>assets<br>  └── js<br><br>themes<br>  └── pancakes<br>  |   └── assets<br>          └── js</pre><p>JS within the top-level assets folder will overwrite identically named JS within the theme assets folder.</p><ol><li>Create resources out of your JS files in your assets folder:</li></ol><pre>{{ $vendor := resources.Get &quot;js/vendor/jquery.min.js&quot; }}<br>{{ $customjs := resources.Get &quot;js/main.js&quot; }}</pre><p>2. Create an array using <a href="https://gohugo.io/functions/slice/">slice</a>:</p><pre>{{ $scripts := slice $vendor $customjs | resources.Concat &quot;app.js&quot; | minify | fingerprint }}</pre><p>In this example, resources.Concat generates the filename “app.js” in the resources directory. <strong>Files are combined based on the argument order.</strong></p><p>Chain minify and fingerprint to reduce page load time and force a cache refresh.</p><p>3. Link to the generated resource</p><pre>&lt;script type=&quot;text/javascript&quot; src=&quot;{{ $scripts.Permalink }}&quot; integrity=&quot;{{ $scripts.Data.Integrity }}&quot; media=&quot;screen&quot;&gt;&lt;/script&gt;</pre><p>Make sure you use integrity to verify the authenticity of files that use a hash (like fingerprinted files).</p><h3>Hugo’s bright future</h3><p>This new version of Hugo added a few other fantastic features, such as <a href="https://gohugo.io/content-management/image-processing/#readout">image processing</a> and the ability to use Go within resources.</p><h4>Resize, crop, and re-sample <strong>programmatically</strong>.</h4><p>A user uploaded image via a CMS like Forestry.io could now result in several generated resources, such as a cropped or scaled thumbnail.</p><p>For example, a cropped thumbnail for a blog archive page:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/739/1*Bbp_zcUPV717biSvVGtVSw.png" /><figcaption>Hugo uses Smartcrop by default</figcaption></figure><p>A full-size version of the image for the actual blog post:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EWqhu1O26maUC-4YLV6EjQ.jpeg" /></figure><p>Cropped thumbnails are essential for a blog and are a standard for content management systems like Wordpress. A blog archive page needs to use cropped or scaled down versions of the post’s featured image to avoid horrendous page load speed from downloading several full-size images.</p><p>One work around for this problem is to upload two variations of the featured image, but now we can simply include image processing within the layout!</p><h4>Using Go within resources</h4><p>This requires further exploring, but this likely means that you could use page or site-level variables to manipulate stylesheets. Users could potentially use front matter to define Sass variables (though you have to be careful with this approach). This is particularly game-changing if you overlay a CMS like Forestry.io and use Data files to provide Wordpress-like theme options. Users could have direct access to modifying the look and feel of their theme without writing any code.</p><h3>Bridging the gap</h3><p>Static site generators are increasingly becoming more accessible to non-developers. <strong>The latest update from Hugo will enable normal users to benefit from the speed and functionality of Hugo without writing a line of code themselves.</strong></p><ul><li>Netlify’s one-click deploy enables simple deployment of Hugo with a pre-installed theme. It also enables contact forms for static sites and simple one-click SSL install.</li><li><a href="https://forestry.io">Forestry.io</a> gives users a familar and easy to use interface while allowing developers to provide simple fields for modifying layouts and styles.</li><li>Hugo’s fast build time, markdown shortcodes, newly added asset pipeline, image processing, and ability to modify stylesheets using front matter, make it a worthy static competitor to Wordpress.</li></ul><h4>What’s missing?</h4><p>This combination allows us to produce a one-click deploy theme that integrates with Forestry.io to provide users with a flexible page builder similar to Wordpress page builders like Divi, Visual Composer, and Beaver Builder.</p><p>In the coming weeks we will release a free, open source Hugo theme that enables users to easily build page layouts without writing a line of code or using Git.</p><p>Follow me on Twitter: <a href="https://twitter.com/BenBozzay">https://twitter.com/BenBozzay</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9266fd3c411e" width="1" height="1" alt=""><hr><p><a href="https://blog.fullstackdigital.com/how-to-cache-bust-and-concatenate-js-and-sass-files-with-hugo-in-2018-9266fd3c411e">How to cache-bust and concatenate JS and SASS files with Hugo in 2018</a> was originally published in <a href="https://blog.fullstackdigital.com">Fullstack Digital</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to use Hugo template variables in SCSS files (in 2018)]]></title>
            <link>https://blog.fullstackdigital.com/how-to-use-hugo-template-variables-in-scss-files-in-2018-b8a834accce?source=rss----9b1e3bc24b6e---4</link>
            <guid isPermaLink="false">https://medium.com/p/b8a834accce</guid>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[sass]]></category>
            <category><![CDATA[static-site-generator]]></category>
            <category><![CDATA[hugo]]></category>
            <category><![CDATA[golang]]></category>
            <dc:creator><![CDATA[Ben Bozzay]]></dc:creator>
            <pubDate>Mon, 11 Mar 2019 15:31:51 GMT</pubDate>
            <atom:updated>2020-09-04T17:24:50.582Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XaMUojlziwq8kneRid9Yjw.png" /></figure><p><a href="https://gohugo.io/news/0.43-relnotes/">Hugo 0.43</a> added the ability to execute a resource as a Go template, meaning template variables can now be used to modify stylesheets.</p><p>With the addition of Hugo Pipes comes default support for SASS/SCSS. One of the biggest advantages of using SCSS is the ability to define variables that are used throughout your stylesheet and organize styles into partial files.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/433/1*tbEjWmyV1jjaU90SBwSXug.png" /></figure><p>The addition of resources.ExecuteAsTemplate in 0.43 means that we could, for example, use our config file to define the values for our SCSS variables!</p><p>Using Hugo’s variables or params in SCSS files could allow a non-technical user to use a CMS like Forestry.io to easily change styles without any understanding of stylesheets or SASS.</p><p>Furthermore, <strong>we could significantly reduce the size of our stylesheet by conditionally importing SCSS (more on this in the next tutorial).</strong></p><p>As our team wraps up development of Pancakes Builder (an open source builder theme for Hugo), we were thrilled with this particular release. Our original solution for user-defined styles was to inline some styles. Now, we’ve refactored the theme to use template variables to define our SCSS variables.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fupscri.be%2F15ee91%3Fas_embed%3Dtrue&amp;dntp=1&amp;url=https%3A%2F%2Fupscri.be%2F15ee91%2F&amp;image=https%3A%2F%2Fe.enpose.co%2F%3Fkey%3DdRXnS9Gplk%26w%3D700%26h%3D425%26url%3Dhttps%253A%252F%252Fupscri.be%252F15ee91%252F%253Fenpose&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=upscri" width="800" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/99f0fa3cb2296dc2f2b564256244f4a0/href">https://medium.com/media/99f0fa3cb2296dc2f2b564256244f4a0/href</a></iframe><p>The theme also contains numerous elements like sliders, accordions, contact forms etc.. However, a user will probably not use all supported elements. Our styles and JS are now conditionally included based on the elements in use.</p><h3>How to use template variables within SCSS</h3><p>Refer to my <a href="https://blog.fullstackdigital.com/how-to-cache-bust-and-concatenate-js-and-sass-files-with-hugo-in-2018-9266fd3c411e">last tutorial</a> on how to use SASS with Hugo in 2018 and Hugo’s new resource functions.</p><ol><li>Add template support to your stylesheet</li></ol><p>We’ll add template support to main.scss, which imports our partial SCSS.</p><pre>{{ $styles := resources.Get “scss/main.scss” | resources.ExecuteAsTemplate “style.main.scss” . | <br>toCSS | <br>minify | <br>fingerprint }}</pre><p><strong>Note: it does not seem like you can currently use this method with partial SCSS files (such as _variables.scss).</strong></p><p>resources.Get creates a new resource object based on a path to a file in the /assets directory. Then, we use resources.ExecuteAsTemplate with the resource type prepended to the name of the file. We add . to pass <a href="https://gohugo.io/templates/introduction/#context-aka-the-dot">the context</a> (more on this later). We then chain the toCSS function (to compile our SCSS to CSS), minify (to reduce file size), and fingerprint for <a href="https://blog.fullstackdigital.com/how-to-cache-bust-and-concatenate-js-and-sass-files-with-hugo-in-2018-9266fd3c411e">cache-busting</a>.</p><p>In the code snippet above, resources.Get generates a file in the resources directory:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/423/1*BggSJbrPKru2qPMp0bNSXQ.png" /><figcaption>In this particular example fingerprinting is enabled, which is why this file name seems weird</figcaption></figure><p>We can now link to the newly generated resource:</p><pre>&lt;link rel=”stylesheet” <br>href=”{{ $styles.Permalink }}” <br>integrity=”{{ $styles.Data.Integrity }}” <br>media=”screen”&gt;</pre><p>Make sure to use Data.Integrity with fingerprint (<a href="https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity">here’s why</a>).</p><p>2. Add Sass variables to main.scss</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/385/1*hu5l1WfbC9IhF0U_6yGKaw.png" /></figure><p>Since we can’t use template variables within our partial files, but we can use them within our main.scss file, we simply need to define our variables at the top of main.scss (above any imported files).</p><p>3. Create Hugo variables or params</p><p>We could use .Params (in our config file), Data files, or even page variables within our stylesheet. It’s best to define site-wide variables in the config file or data files.</p><ul><li>Using config.toml:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/257/1*fl_5Wb-rEaqU60z82cSCsg.png" /></figure><p>In our config file we add a few params: container_size with a value of 1080px and container_size_wide with a value of 1350px.</p><p>Now we include these values in main.scss using .Site.Params:</p><pre>{{ .Site.Params.container_size | default &quot;1100px&quot; }}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/745/1*G5-foiiul0_c8BncuavMag.png" /></figure><p>Since we will reference our $container style variable throughout our template, we do not want an empty value.</p><p>On the off chance that a user does not set a value for the variable, the default value will be used. <strong>It is critical that you have fallbacks for style variables that use template variables/params!</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/768/1*1ROIMinajcdHLNBCH8-mIg.png" /></figure><p>In our _layout.scss file we reference our SCSS variable as normal, but it’s now based on the value for the param in .config.toml!</p><ul><li>Using a data file and YAML/front matter</li></ul><p>Our data file “colors” will be used to set the primary color variable used in our SCSS files.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/765/1*qYJ31ZLXBVZgJA7yjS5prw.png" /><figcaption><a href="https://anotheruiguy.gitbooks.io/sassintherealworld_book-i/handy-tools/default-flag.html">Using !default in SCSS</a></figcaption></figure><p>Our data file has several fields:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/209/1*Kbr3YYLRLMTsYR7BwTJN5Q.png" /></figure><p>We’ll referenceprimary_color using:</p><pre>{{ .Site.Data.color.primary_color | default &quot;#7a8288&quot; }}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/744/1*KoY3QwJczYk7C7djy3_ufA.png" /></figure><p>Now our $primary-color SCSS variable is based on the value for the primary_color variable in our data file!</p><h4>Limiting potential values and maintaining valid variables</h4><p>We can use default to provide a fallback for empty values. However, we also need to make sure that only supported values are used.</p><p>For example, our color fields require a # if a hex value is used. We don’t want to preprend this to our template variable because the user might decide to use rgba instead.</p><p>We can use field types in a CMS like Forestry to control field values based on the field type.</p><p>For example, we can use the color picker field to generate a hex code with the # automatically added:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/749/1*VVlDi7yocu81ctoh4bZjZA.png" /></figure><p>We could also limit supported values using a select drop down field:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/650/1*GpJ9WlwdyvZp-LzrNmmsVw.png" /></figure><h3>What’s next?</h3><p>The next tutorial will cover how to signficantly reduce CSS and JS file sizes by conditionally including CSS based on the components used on the page. <a href="https://twitter.com/BenBozzay">Follow me on Twitter</a> to get notified when the next tutorial is ready!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b8a834accce" width="1" height="1" alt=""><hr><p><a href="https://blog.fullstackdigital.com/how-to-use-hugo-template-variables-in-scss-files-in-2018-b8a834accce">How to use Hugo template variables in SCSS files (in 2018)</a> was originally published in <a href="https://blog.fullstackdigital.com">Fullstack Digital</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Create a Flawless Responsive Post Grid with Flexbox]]></title>
            <link>https://blog.fullstackdigital.com/how-to-create-a-flawless-responsive-post-grid-with-flexbox-e5c7cc9d28e?source=rss----9b1e3bc24b6e---4</link>
            <guid isPermaLink="false">https://medium.com/p/e5c7cc9d28e</guid>
            <category><![CDATA[flexbox]]></category>
            <category><![CDATA[wordpress]]></category>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[wordpress-web-development]]></category>
            <dc:creator><![CDATA[Ben Bozzay]]></dc:creator>
            <pubDate>Mon, 11 Mar 2019 15:31:43 GMT</pubDate>
            <atom:updated>2022-02-09T03:00:22.883Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DPlsCGcT2pEYRYAMzbJRqg.png" /></figure><p>Today we’ll learn the best way to create a grid to easily display content, like <strong>Wordpress posts</strong>, with minimal media queries required for the responsive views.</p><p>We frequently see websites using a multi-row setup to organize similar content:</p><pre>&lt;div class=&quot;row&quot;&gt;<br>  &lt;div class=&quot;col&quot;&gt;<br>    ...<br>  &lt;/div&gt;<br>  &lt;div class=&quot;col&quot;&gt;<br>    ...<br>  &lt;/div&gt;<br>&lt;/div&gt;</pre><pre>&lt;!--next row--&gt;<br>&lt;div class=&quot;row&quot;&gt;<br>  &lt;div class=&quot;col&quot;&gt;<br>    ...<br>  &lt;/div&gt;<br>  &lt;div class=&quot;col&quot;&gt;<br>    ...<br>  &lt;/div&gt;<br>&lt;/div&gt;</pre><p>Using multiple rows complicates the responsive layout significantly:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2zo-uVJc9E9wl3IvrQCaZg.gif" /><figcaption>Two rows with 5 columns in each row</figcaption></figure><p>Notice how extra whitespace is created in responsive views due to columns being seperated into rows. The columns don’t fill up the remaining space, so some screen sizes have an odd looking whitespace.</p><p>On mobile, some columns appear to have a bigger <strong>vertical whitespace</strong> because of the row’s margin-bottom. This looks sloppy!</p><p>We could adjust the media queries for the rows and columns, but this requires a lot of tweaking to get right.</p><p>Using flexbox, we can easily create a <a href="https://codepen.io/fullstackdigital/pen/MBzKXj">responsive grid</a>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fOBfBty4im92gCdxfKV5dw.gif" /><figcaption>View the <a href="https://codepen.io/fullstackdigital/pen/MBzKXj">codepen</a> for this grid</figcaption></figure><p>In many situations, you’d want to use <strong>Ajax-load-more</strong> or filters to dynamically display content on a page, so a grid-layout would be needed.</p><figure><a href="https://bossfreelance.com"><img alt="" src="https://cdn-images-1.medium.com/max/397/1*Sm9xbsYc9rc-33cQbi6Tfw.jpeg" /></a></figure><p>For example, as part of our <a href="https://fullstackdigital.com/work/code-open-source/">web presence overhaul</a> for {code}, Open Source at Dell Technologies, we created a page for <strong>dynamically displaying posts based on filter and sorting options.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0FeOldgDf6xt2s7x3-aAsg.gif" /><figcaption>Projects can be viewed through page filtering or sorting.</figcaption></figure><p>We created a grid layout so that posts could easily be appended without breaking the layout. In this tutorial, you’ll learn how to re-create this post grid.</p><h3>Creating the responsive grid</h3><p>Making the grid items responsive is easy using Flexbox.</p><p>Let’s examine the wrapping elements:</p><pre>&lt;div class=&quot;container&quot;&gt;<br>      &lt;div class=&quot;grid-row&quot;&gt;<br>        ...</pre><p>All of our <strong>grid-items</strong> (columns) are wrapped with one row and one container.</p><pre>.container {<br>  max-width: 1335px;<br>  margin: 0 auto;<br>}</pre><pre>.grid-row {<br>  display: flex;<br>  flex-flow: row wrap;<br>  justify-content: flex-start;<br>}</pre><p>Our <strong>container</strong> CSS sets the total max-width. Using display: flex, our <strong>grid-row</strong> stretches to the full size of the container.</p><p>We use flex-flow: wrap to designate that child divs (our columns/grid-items) should wrap if they exceed the width of the row. Then, flex-flow: row means our grid-items will flex from left to right. <em>If we used flex-flow: column, our child divs would flex from top down.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/502/1*Zs2orbGUA9ir3RACpwmNLA.png" /><figcaption>Source: <a href="https://css-tricks.com/almanac/properties/j/justify-content/">https://css-tricks.com/almanac/properties/j/justify-content/</a></figcaption></figure><p>Then, we use justify-content: flex-start because we want our grid-items to line up next to each-other at the start of the row.</p><h3>Creating the grid item</h3><p>Each grid-item should have identical height, so we set a height of 550px:</p><pre>.grid-item {<br>  height: 550px;<br>  flex-basis: 20%;<br>  -ms-flex: auto;<br>  width: 259px;<br>  position: relative;<br>  padding: 10px;<br>  box-sizing: border-box;<br>}</pre><p>On desktop views, we set a flex-basis of 20% for each grid-item. This means that 5 grid-items will display on the same level. The 6th grid-item will wrap to the next “row” since we are using flex-wrap: wrap in our <strong>grid-row</strong>.</p><p>We set a width of 259px for certain browsers that require a width to be defined. However, the actual width is set by flex-basis.</p><h4>Media Queries</h4><p>We only need a few media queries on our .grid-item. We just need to define the flex-basis on each desired screen-width.</p><p>Based on the <strong>content within our grid-items</strong>, we used these media queries:</p><pre>.grid-item {<br>  height: 550px;<br>  flex-basis: 20%;<br>  -ms-flex: auto;<br>  width: 259px;<br>  position: relative;<br>  padding: 10px;<br>  box-sizing: border-box;<br>}</pre><pre><a href="http://twitter.com/media">@media</a>(max-width: 1073px) {<br>   .grid-item {<br>    flex-basis: 33.33%;<br>  }<br>}</pre><pre><a href="http://twitter.com/media">@media</a>(max-width: 815px) {<br>  .grid-item {<br>    flex-basis: 50%;<br>  }<br>}</pre><pre><a href="http://twitter.com/media">@media</a>(max-width: 555px) {<br>  .grid-item {<br>    flex-basis: 100%;<br>  }<br>}</pre><p>On the smallest screen-width, we use a flex-basis of 100% to make our <strong>grid-item</strong> the full-width of the <strong>grid-row</strong>.</p><p>If you’re building for mobile-first, you should adjust your CSS this way:</p><pre>.grid-item {<br>  height: 550px;<br>  flex-basis: 100%;<br>  -ms-flex: auto;<br>  width: 259px;<br>  position: relative;<br>  padding: 10px;<br>  box-sizing: border-box;<br>}</pre><pre>@<a href="http://twitter.com/media">media</a>(min-width: 1073px) {<br>  .grid-item {<br>    flex-basis: 33.33%;<br>  }<br>}</pre><pre><a href="http://twitter.com/media">@media</a>(min-width: 815px) {<br>  .grid-item {<br>    flex-basis: 50%;<br>  }<br>}</pre><p>Our .grid-item defaults to a flex-basis of 100% unless the screen size is a large tablet or a laptop/desktop.</p><p>With either approach, we only need to change the flex-basis for a few screen-widths to achieve a grid.</p><h4>Cross-browser support</h4><p>The CSS in this tutorial doesn’t cover all of the vendor prefixes required when using flexbox. If you’re using a build tool, make sure you use PostCSS with autoprefixer to automatically add all the required vendor prefixes. You can also generate these vendor prefixes by pasting your CSS into an autoprefixer tool <a href="https://autoprefixer.github.io/">like this one</a>.</p><h3>Finishing up</h3><p>View the <a href="https://codepen.io/fullstackdigital/pen/bjKoqK">full source code</a>, which also includes the styles for the content in each grid-item and the hover/grow effects. <a href="https://twitter.com/BenBozzay">Follow me on Twitter</a> for more upcoming tutorials, like <strong>achieving a perfect </strong><a href="https://devboss.io/learn/build-fast-websites/why-websites-load-slowly"><strong>page speed</strong></a><strong> score</strong> in Google PageSpeed insights.</p><figure><a href="https://bossfreelance.com"><img alt="" src="https://cdn-images-1.medium.com/max/397/1*Sm9xbsYc9rc-33cQbi6Tfw.jpeg" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e5c7cc9d28e" width="1" height="1" alt=""><hr><p><a href="https://blog.fullstackdigital.com/how-to-create-a-flawless-responsive-post-grid-with-flexbox-e5c7cc9d28e">How to Create a Flawless Responsive Post Grid with Flexbox</a> was originally published in <a href="https://blog.fullstackdigital.com">Fullstack Digital</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Automatically Generate and Inline Critical CSS with Hugo Pipes]]></title>
            <link>https://blog.fullstackdigital.com/how-to-automatically-generate-and-inline-critical-css-with-hugo-pipes-48c52c2d8f82?source=rss----9b1e3bc24b6e---4</link>
            <guid isPermaLink="false">https://medium.com/p/48c52c2d8f82</guid>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[hugo]]></category>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[css]]></category>
            <dc:creator><![CDATA[Ben Bozzay]]></dc:creator>
            <pubDate>Mon, 11 Mar 2019 15:31:32 GMT</pubDate>
            <atom:updated>2020-09-04T17:19:06.955Z</atom:updated>
            <content:encoded><![CDATA[<p>Today I’m going to show you how to use Hugo pipes to extract critical path CSS and generate a stylesheet based on the styles that are actually in use on the website.</p><p>One of the best ways to optimize a website for load speed is to inline critical CSS and defer loading of non-critical CSS. Google PageSpeed insights refers to this optimization as “<strong>eliminating render-blocking JavaScript and CSS in above-the-fold content.</strong>”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/975/1*x-poSDw5EZEaaj8KPCapIg.jpeg" /></figure><p>You can achieve a much faster load speed by inlining styles required to render the top area of your website in the &lt;head&gt; of each page’s HTML:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/530/1*i-fmAmIe3utCvMpurV_5Dw.png" /></figure><p>However, extracting critical CSS for larger websites with many unique page layouts is easier said than done.</p><p>As we work on the initial release of <strong>Pancakes Builder</strong>, a free visual website builder for <a href="https://gohugo.io/">Hugo</a>, we had to solve the issue of achieving a fast page load speed for every variation of a page that a user might decide to build.</p><p>Pancakes Builder leverages a modular design where sections are stacked to construct the actual layout and content. For non-templated pages that are built with stacks of sections, <strong>we had to solve some pretty substantial optimization issues:</strong></p><ul><li>Normally, a user has to download the entire stylesheet before the page is rendered and this causes a noticeable delay in the first page load.</li></ul><p><strong>Solution</strong>: Inline critical CSS so that the render blocking CSS loads with the page’s HTML. Then, load non-critical CSS asynchronously.</p><ul><li>Some users of Pancakes Builder will build websites that never use elements supported by the builder — accordions, sliders, etc.. We don’t want to bundle styles for unused components.</li></ul><p><strong>Solution</strong>: Generate a cacheable site-wide stylesheet composed <strong>only of the styles of all non-render blocking sections</strong>.</p><h3>Creating a Modular Layout</h3><p>Modular layouts allow a user to build a unique page by stacking sections. If we adjust our Hugo theme to use a modular layout we can do a lot of cool stuff.</p><p>To create a modular layout, we’ll adjust our template to use partial files to build pages by stacking sections.</p><blockquote>Sections are partial files with a predefined layout.</blockquote><p>We can then use front matter, or another preferred method, to designated what sections appear on our page and in what order.</p><p>For example, the Forestry content management system supports building flexible layouts using their <a href="https://forestry.io/docs/settings/fields/blocks/">blocks widget</a>, which basically provides a simple UI for repeating front-matter fields:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/674/1*csTzRZFp19ZEOpzCO_BXTA.jpeg" /><figcaption>Source: <a href="https://forestry.io/docs/settings/fields/blocks/">https://forestry.io/docs/settings/fields/blocks/</a></figcaption></figure><p>The page front-matter for these blocks would probably look like this:</p><pre>blocks:<br>  - template: &quot;hero-section&quot;<br>  - template: &quot;body-copy&quot;<br>  - template: &quot;hero-section&quot;<br>  - template: &quot;media-feature&quot;<br>  - template: &quot;media-feature&quot;<br>  - template: &quot;media-feature&quot;<br>  - template: &quot;call-to-action&quot;</pre><p>Partial files with pre-built layouts are then added based on the template name in the front-matter:</p><pre>{{ range .Params.page_sections }}<br>    {{ if eq &quot;hero-section&quot; .template }}<br>        {{ partial &quot;blocks/hero&quot; . }}<br>    {{ end }}<br>    {{ if eq &quot;call-to-action&quot; .template }}<br>        {{ partial &quot;blocks/cta&quot; . }}<br>    {{ end }}<br>{{ end }}</pre><p>We can apply this same concept to generating the critical and non-critical styles associated with the used blocks across our website.</p><h4>1. Build a flexible layout with front matter</h4><p>In our page front matter, we add a range called “stacks” with a few templates:</p><pre>---<br>title: &quot;Home Page&quot;<br>stacks:<br>- template: header-builder<br>- template: hero-builder-section<br>- template: contact-builder-section<br>- template: footer-builder</pre><p>These templates will be used to specify partial files. Notice that we are even including the header and footer in our range. This is because we will use this range to extract CSS from all used sections.</p><p>We can then create a loop of sections in our main layout file:</p><pre><strong>// Check if the &quot;stacks&quot; key exists in our front matter</strong></pre><pre>{{ if .Params.stacks }}</pre><pre><strong>// Iterate through each stack</strong><br>{{ range $index, $stacks := .Params.stacks }}</pre><pre>{{ if in .template &quot;header&quot; }}<br>&lt;header&gt;<br>  ...<br>&lt;/header&gt;</pre><pre>{{ else if in .template &quot;section-hero-image&quot; }}<br>&lt;section&gt;<br>  &lt;div class=&quot;hero&quot;&gt;<br>    ...<br>  &lt;/div&gt;<br>&lt;/section&gt;</pre><pre>{{ else if in .template &quot;section-form&quot; }}<br>&lt;section&gt;<br>  &lt;form&gt;<br>    ...<br>  &lt;/form&gt;<br>&lt;/section&gt;</pre><pre>{{ else if in .template &quot;footer&quot; }}</pre><pre>&lt;footer&gt;<br>...<br>&lt;/footer&gt;<br>...</pre><p><strong>The display order of the sections on our page will match the order in our front-matter. </strong>For the purposes of this tutorial, I have not included many different section variations.</p><h4>2. Add classes to HTML</h4><p>We’ll need to append a unique class to each section in our HTML. Let’s generate a few unique classes:</p><ol><li>One class designating the <strong>template name</strong> used in our front matter. We’ll need this for our base styling (styles used for multiple sections).</li><li>One class with the unique <strong>section identifier</strong>. We’ll need this for our non-critical stylesheet and to apply unique styles to a single section.</li></ol><p>In our range we’ll add the .Scratch values to generate classes for each section.</p><pre>{{ range $index, $stacks := .Params.stacks }}</pre><pre>{{ $.Scratch.Set &quot;section_base&quot; .template }}</pre><pre>{{ $section_style := print $index &quot;-&quot; .template }}<br>{{ $.Scratch.Set &quot;section_style&quot; $section_style }}</pre><pre>{{ $.Scratch.Set &quot;page_hash&quot; .UniqueID | urlize }}</pre><pre>{{ $id := print &quot;section-&quot; $index }}<br>{{ $.Scratch.Set &quot;section_id&quot; $id}}</pre><pre>{{ if in .template &quot;header&quot; }}<br>&lt;header id=&quot;{{ $.Scratch.Get &quot;section_id&quot; }}&quot; class=&quot;{{ $.Scratch.Get &quot;section_base&quot; }} c-{{ $.Scratch.Get &quot;section_style&quot; }} p-{{ $.Scratch.Get &quot;page_hash&quot; }}&quot;&gt;<br>  ...<br>&lt;/header&gt;<br>{{ else if in .template &quot;section-form&quot; }}<br>&lt;section id=&quot;{{ $.Scratch.Get &quot;section_id&quot; }}&quot; class=&quot;{{ $.Scratch.Get &quot;section_base&quot; }} c-{{ $.Scratch.Get &quot;section_style&quot; }} p-{{ $.Scratch.Get &quot;page_hash&quot; }}&quot;&gt;<br>  &lt;form&gt;<br>    ...<br>  &lt;/form&gt;<br>&lt;/section&gt;<br>...</pre><p><em>We use </em><em>.Scratch instead of normal variables so we can easily access these variables in our partial files and change their values from within our partials.</em></p><p>Since we’ve attached an index to our range (think of this as a “counter”), we can generate a <strong>section_id</strong> based on the order of our section within the range:</p><pre>{{ $id := print &quot;section-&quot; $index }}<br>{{ $.Scratch.Set &quot;section_id&quot; $id}}</pre><p>The output will look like this: section-1.</p><p>We can also create a general class based on our section-template used for our <strong>base CSS:</strong></p><pre>{{ $.Scratch.Set &quot;section_base&quot; .template }}</pre><p>The output will look like this: section-form.</p><p>For specific section styling, we’ll create another scratch called section_base that prepends “c” with the index number and template name:</p><pre>{{ $section_style := print $index &quot;-&quot; .template }}<br>{{ $.Scratch.Set &quot;section_style&quot; $section_style }}</pre><p>The output will look like this: c-2-section-form.</p><p>We’ll create a scratch called page_hash with the page <a href="https://gohugo.io/variables/page/#page-variables">UniqueID</a> and add this unique identifier to each section in our range:</p><pre>{{ $.Scratch.Set &quot;page_hash&quot; .UniqueID | urlize }}</pre><p>This is necessary so we can target unique sections on other pages.</p><p><strong>Example output in the HTML:</strong></p><pre>&lt;header id=&quot;section-0&quot; class=&quot;c-header-builder p-123sdf6521341dsfa&quot;&gt;<br>...<br>&lt;/header&gt;</pre><pre>&lt;section id =&quot;section-1&quot; class=&quot;form-builder-section c-1-form-builder-section p-123sdf6521341dsfa&quot;&gt;<br>...<br>&lt;/section&gt;</pre><p>In our stylesheet, we can use .form-builder section {…} to add the base styles for our form. We can then use .p-123sdf6521341dsfa.c-1-form-builder-section {…} in our stylesheet to target the unique styles for a specific form-builder section on a specific page.</p><p>We can uniquely target sections in our stylesheet while applying base styles if needed:</p><pre>/*base header style*/<br>header {<br>  background: #ffffff;<br>  height: 80px;<br>}</pre><pre>/*override the base color for this particular page and section*/<br>.c-0-header-builder.p-123sdf6521341dsfa {<br>  background: #efefef;<br>}</pre><p>Later in this tutorial, we will use template variables to specify these classes automatically:</p><pre>header {<br>  background: #efefef;<br>  height: 80px;<br>}</pre><pre>/*header style for this particular page and section*/<br>.c-{{ $.Scratch.Get &quot;section_class&quot; }}.p-{{ $.Scratch.Get &quot;page_hash&quot; }} {<br>  background: #efefef;<br>}</pre><p>Now that our HTML is generated, we can focus on generating styles.</p><h3><strong>Generating our critical inline style</strong></h3><p>We create partial files for a typical section and unique elements. The folder structure looks something like this:</p><pre>partials<br>├── sections<br>│   ├── section<br>│   │   ├── style.html<br>│   │   ├── base.html</pre><ul><li><strong>Style.html: </strong>contains the unique style for a specific section and overrides the base style.</li><li><strong>Base.html: </strong>the standardized base style of our section. The default color, size, etc.</li></ul><p>Our overall strategy is to iterate through each section on each page. We’ll then grab the individualized section style for each section. Then, we will include the <strong>base.html</strong> only once. and the base style for whatever elements are in use in that section.</p><h4><strong>1. Create css_gen.html with section styles</strong></h4><p>Let’s start by creating a partial layout file that contains our generated CSS. We’ll use <a href="https://gohugo.io/hugo-pipes/">Hugo pipes</a> to generate a resource from this file later on.</p><p>We’ll include this partial file in our inline header style (for critical css) and our non-critical stylesheet that we load asynchronously.</p><p><strong>Add this partial between </strong><strong>&lt;style&gt; tags in the head and footer of your site:</strong></p><pre><strong>&lt;style&gt;</strong>{{ partial “site/css_gen.html” (dict “page” . “global” $ ) }}<strong>&lt;/style&gt;</strong></pre><p>We’ll then pass the current context using dict so that we can use page-level and global variables in our partial file. We can now access page context (“the dot”) using .page and global context ($) using .global.</p><p>Normally, <strong>outside of a partial file</strong> we can access page params with {{ .Params }}. In our css_gen partial file, however, we will access page params with {{ .page.Params }}.</p><p>Our <strong>css_gen.html</strong> file will start by looking similar to the main layout file with our section loop:</p><pre><strong>// get each page</strong><br>{{ range $index, $stacks := .page.Site.Pages }}</pre><pre><strong>// check if the &quot;stacks&quot; key exists in our front matter</strong></pre><pre>{{ if .Params.stacks }}</pre><pre><strong>// iterate through each stack</strong><br>{{ range $index, $stacks := .Params.stacks }}</pre><pre><strong>// set a section ID based on the index</strong><br>{{ $.page.Scratch.Set &quot;section_index&quot; $index }}</pre><pre><strong>// set one class based on the front matter template value</strong><br>{{ $.page.Scratch.Set &quot;section_base&quot; .template }}</pre><pre><strong>// set a class with index prepended</strong><br>{{ $section_style := print &quot;c-&quot; $index &quot;-&quot; .template }}<br>{{ $.page.Scratch.Set &quot;section_style&quot; $section_style }}</pre><pre><strong>// set a class with page uniqueID<br></strong>{{ $.Scratch.Set &quot;page_hash&quot; .UniqueID | urlize }}</pre><pre>{{ if in .template &quot;header&quot; }}<br>{{ partial &quot;sections/header/style.html&quot; (dict &quot;page&quot; . &quot;global&quot; $ ) | safeCSS }}</pre><pre>{{ else if in .template &quot;section-form&quot; }}<br>{{ partial &quot;sections/section-form/style.html&quot; (dict &quot;page&quot; . &quot;global&quot; $ ) | safeCSS }}</pre><pre>{{ else if in .template &quot;footer&quot; }}<br>{{ partial &quot;sections/footer/style.html&quot; (dict &quot;page&quot; . &quot;global&quot; $ ) | safeCSS }}<br>...</pre><p>The main difference is the included style partial files, which use dictto pass the context and safeCSS to designate safe output.</p><p>In our page front matter, we can designate some styles for our specific section:</p><pre>stacks:<br>  - template: &quot;header&quot;<br>  - template: &quot;section-form&quot;<br>    background-color: &quot;#efefef&quot;<br>  - template: &quot;footer&quot;</pre><p>Our style.html for <strong>section-form</strong> looks like this:</p><pre>{{ if .page.background_color }}</pre><pre>.{{ .global.page.Scratch.Get &quot;section_class&quot; }}.p-{{ .global.page.Scratch.Get &quot;page_uniqueid&quot; }} {<br>  background-color: {{ .page.background_color | default &quot;#ffffff&quot; }};<br>}</pre><pre>{{ end }}</pre><p>You can use default values, isset, with, and other Hugo functions to control default and conditional stylesheet content.</p><p>Output:</p><pre>.c-1-section-form.p-123sdf6521341dsfa {<br>  background-color: #efefef;<br>}</pre><h4>2. Add base styles to css_gen.html</h4><p>Base styles are only included once, while section styles are included each time a style is used for a particular section. We can use .Scratch to “activate” a base style and include the style outside of our range:</p><pre>{{ range $index, $stacks := .page.Site.Pages }}<br>{{ if .Params.stacks }}<br>{{ range $index, $stacks := .Params.stacks }}<br>...</pre><pre>{{ else if in .template &quot;section-form&quot; }}<br>{{ partial &quot;sections/section-form/style.html&quot; (dict &quot;page&quot; . &quot;global&quot; $ ) | safeCSS }}</pre><pre>{{ $.page.Scratch.Set &quot;form_base_css&quot; true }}<br>...<br><strong>// End of stacks range</strong><br>{{ end }}<br><strong>// End stacks conditional</strong><br>{{ end }}<br><strong>// End of page range</strong><br>{{ end }}</pre><pre><strong>// Include the base CSS for the form section only once</strong><br>{{ if eq ( $.page.Scratch.Get &quot;section_base_css&quot; ) true }}<br>{{ partial &quot;sections/section-form/base.html&quot; (dict &quot;page&quot; . &quot;global&quot; $ ) }}<br>{{ end }}<br>...</pre><p>Using .Scratch, we can choose to include the base CSS if the section exists. Scratch allows us to specify a variable within our range and pass that value outside of the range.</p><h4>3. Specify critical and non-critical CSS</h4><p>Our current css_gen file doesn’t specify critical or non-critical CSS. To do this, we need to limit our range to the first 2 sections for our critical CSS. Our non-critical CSS range will need to a range greater than 2. Since we want to use the same css_gen file and avoid duplicating work, we’ll need to adjust our current stacks range.</p><blockquote><strong>Don’t Repeat Yourself</strong> is the perennial mantra of the software developer. It doesn’t mean you should never do the same thing twice, but instead refers to having a single, authoritative source of truth for every piece of information used in your software. — <a href="https://forestry.io/blog/data-relationships-in-hugo/">DJ Walker</a></blockquote><p>Let’s adjust where we include our partial file. <strong>In our head where we specify inline critical CSS:</strong></p><pre>{{ $.Scratch.Set &quot;is_critical&quot; true }}</pre><pre>{{ $env := getenv &quot;HUGO_ENV&quot; }}</pre><pre>{{ if or (.Site.IsServer) (eq $env &quot;&quot;) }}</pre><pre>&lt;style&gt;{{ partial &quot;site/css_gen.html&quot; (dict &quot;page&quot; . &quot;global&quot; $ ) | safeCSS }}&lt;/style&gt;</pre><pre>{{ end }}</pre><p>We add a new scratch allowing us to pass a true/false value to our partial file.</p><p>We include an environment variable so that we can check if we’re in production or staging and then output different content. We use .IsServer to check if we’re using hugo server locally. We’ll use this more later on, but for now just know that there are certain functions we only want to use in our staging and local environments.</p><p><strong>In our footer file where we include non-critical CSS:</strong></p><pre>{{ $.Scratch.Set &quot;is_critical&quot; false }}</pre><pre>{{ partial &quot;site/css_gen.html&quot; (dict &quot;page&quot; . &quot;global&quot; $ ) }}</pre><pre><strong>// For IsServer just inline the style</strong></pre><pre>{{ $env := getenv &quot;HUGO_ENV&quot; }}</pre><pre>{{ if or (.Site.IsServer) (eq $env &quot;&quot;) }}</pre><pre>&lt;style&gt;{{ partial &quot;site/css_gen.html&quot; (dict &quot;page&quot; . &quot;global&quot; $ ) | safeCSS }}&lt;/style&gt;</pre><pre>{{ end }}</pre><p>In our footer, we set is_critical to false. We’ll add a conditional statement within our range:</p><pre><strong>// Get this current page UniqueID</strong><br>{{ $this_uniqueid := .page.UniqueID | urlize }}<br>{{ range $index, $stacks := .page.Site.Pages }}</pre><pre><strong>// Get the unique ID for each page<br></strong>{{ $page_uniqueid:= .UniqueID | urlize }}<br>{{ if .Params.stacks }}<br>{{ range $index, $stacks := .Params.stacks }}</pre><pre><strong>// Check for true/false value in outer template</strong><br>{{ if eq ($.page.Scratch.Get &quot;is_critical&quot;) true }}</pre><pre><strong>// Get the styles for this page with an index of 0 and 1</strong><br>{{ $.page.Scratch.Set &quot;style_index&quot; (and (eq $this_uniqueid $page_uniqueid) (le $index 1)) }}</pre><pre><strong>// Non-critical CSS</strong><br>{{ else }}</pre><pre><strong>// Get the styles for all sections on all pages with an index greater than 1<br></strong>{{ $.page.Scratch.Set &quot;style_index&quot; (gt $index 1) }}</pre><pre>{{ end }}</pre><pre><strong>// Our condition is now based on a scratch value<br></strong>{{ if $.page.Scratch.Get &quot;style_index&quot; }}</pre><pre><strong>// Include partial files<br>...</strong></pre><p>Two UniqueIDs are added so that we can get the inlined critical CSS. Then, we use the <strong>is_critical</strong> scratch value to specify our <strong>style_index</strong> scratch value.</p><p>The conditional for our critical CSS looks like this:</p><pre>...<br>{{ if and (eq $this_uniqueid $page_uniqueid) (le $index 1) }}<br>...</pre><pre>{{ else if in .template &quot;section-form&quot; }}<br>{{ partial &quot;sections/section-form/style.html&quot; (dict &quot;page&quot; . &quot;global&quot; $ ) | safeCSS }}</pre><pre>{{ $.page.Scratch.Set &quot;form_base_css&quot; true }}<br>...</pre><p>If the <strong>Unique ID</strong> of this page equals the <strong>Unique ID</strong> in our current range, the resulting style.html and base.html for sections 0 and 1 will be inlined in the &lt;head&gt; of our template.</p><p>The condition for our non-critical CSS looks like this:</p><pre>...<br>{{ if gt $index 1 }}<br>...</pre><pre>{{ else if in .template &quot;section-form&quot; }}<br>{{ partial &quot;sections/section-form/style.html&quot; (dict &quot;page&quot; . &quot;global&quot; $ ) | safeCSS }}</pre><pre>{{ $.page.Scratch.Set &quot;form_base_css&quot; true }}<br>...</pre><p>style.html and base.html for all <strong>non-critical</strong> sections on <strong>all pages</strong> are included.</p><h3>Using PostCSS and asset pipelines in production</h3><p>Now that we’ve generated our HTML and set up our critical and non-critical CSS generation, we can focus on processing our CSS using Hugo’s resource functions.</p><h4>1. Create critical and non-critical stylesheets</h4><p>In <strong>assets/scss/</strong> we’ll create a critical and non-critical stylesheet with the same partial file included:</p><pre><strong>// in assets/scss/critical.scss and assets/scss/non-critical.scss</strong></pre><pre>{{ partial “site/css_gen.html” (dict “page” . “global” $ ) }}</pre><p><strong><em>Note</em></strong><em>: make sure you place your files in the assets directory since we are using Resource functions. Also, Resource functions respect Hugo’s </em><a href="https://gohugo.io/templates/lookup-order/#readout"><em>lookup order</em></a><em>, so you can place the associated assets in your theme assets folder or the top-level assets folder.</em></p><h4>2. Set up Hugo Pipes</h4><p>Let’s go back to our head where we include our critical CSS:</p><pre>{{ $.Scratch.Set &quot;is_critical&quot; true }}<br>{{ $env := getenv &quot;HUGO_ENV&quot; }}</pre><pre><strong>// Inline uncompressed styles if we&#39;re in a dev environment<br></strong>{{ if or (.Site.IsServer) (eq $env &quot;&quot;) }}<br>&lt;style&gt;{{ partial &quot;site/css_gen.html&quot; (dict &quot;page&quot; . &quot;global&quot; $ ) | safeCSS }}&lt;/style&gt;<br>{{ end }}</pre><pre><strong>// Inline minified and PostCSS styles if we&#39;re in production or have set a testing param<br></strong>{{ if or (eq $env &quot;production&quot;) (eq .Site.Params.postcss_testing true) }}</pre><pre><strong>// Generate a resource and inline the resulting processed CSS<br></strong>{{ $critical := resources.Get &quot;scss/critical.scss&quot; | resources.ExecuteAsTemplate &quot;style.critical.scss&quot; . | toCSS |postCSS | minify }}</pre><pre><strong>// Display the content from our resource<br></strong>&lt;style class=&quot;critical&quot;&gt;{{ (slice $critical | resources.Concat &quot;style.scss&quot;).Content | safeCSS }}&lt;/style&gt;</pre><pre>{{ end }}</pre><p>We can use Hugo pipelines to generate a CSS resource from our HTML so we can minify our output and add vendor prefixes. Otherwise our inlined CSS will have significant whitespace and won’t be minified. If we’re using hugo server we’ll just inline the HTML instead of processing a resource each time we save the site.</p><p><strong>I recommend adding a </strong><strong>postcss_testing parameter so you can test the critical and non-critical CSS processing in your dev environment.</strong></p><p>If you don’t care about vendor prefixes, you can probably just avoid this step entirely (only for critical CSS) and use the new (<a href="https://github.com/gohugoio/hugo/releases/tag/v0.47">0.47</a>) minify flag to compress your HTML.</p><p><strong>Let’s go back to our footer where we include our non-critical CSS:</strong></p><pre>{{ $.Scratch.Set &quot;is_critical&quot; false }}<br>{{ partial &quot;site/css_gen.html&quot; (dict &quot;page&quot; . &quot;global&quot; $ ) }}<br>{{ $env := getenv &quot;HUGO_ENV&quot; }}</pre><pre><strong>// Inline the style if we&#39;re in a dev environment</strong><br>{{ if or (.Site.IsServer) (eq $env &quot;&quot;) }}<br>&lt;style&gt;{{ partial &quot;site/css_gen.html&quot; (dict &quot;page&quot; . &quot;global&quot; $ ) | safeCSS }}&lt;/style&gt;<br>{{ end }}</pre><pre><strong>// Include a link to the non-critical stylesheet in production<br></strong>{{ if or (eq $env &quot;production&quot;) (eq .Site.Params.postcss_testing true) }}</pre><pre>{{ $noncritical := resources.Get &quot;scss/noncritical.scss&quot; | resources.ExecuteAsTemplate &quot;noncritical.scss&quot; . | toCSS | postCSS | minify | fingerprint }}</pre><pre>&lt;link rel=&quot;stylesheet&quot; href=&quot;{{ $noncritical.Permalink }}&quot; media=&quot;screen&quot;&gt;</pre><pre>{{ end }}</pre><p>Our non-critical stylesheet reference is similar, but we include a link to the stylesheet instead of inlining it. Additionally, we use fingerprint for cache-busting. For a more comprehensive tutorial on Hugo pipes, read <a href="https://regisphilibert.com/blog/2018/07/hugo-pipes-and-asset-processing-pipeline">this tutorial</a> from Regis.</p><h4><strong>Sample critical output with PostCSS:</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zwxmRb6q9od1aRIvMVEzXQ.png" /></figure><p>Notice that sections 0 and 1 are included and have the same pageID.</p><h4><strong>Non-critical stylesheet with PostCSS, fingerprint, and minify:</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cnASb3r24Cv9FiBngJsuhg.png" /></figure><p>Notice that sections with an index greater than 2 are included and there are many different page IDs referenced in the stylesheet.</p><h3>Wrapping up</h3><p>In this tutorial I’ve included a more simplified version of building sections with stacks of sections (blocks, partial files etc.).</p><p>As I’m developing Pancakes Builder, I actually include only one partial section layout instead of multiple pre-built section layouts (like section-form). Then, I use front-matter to make each section completely unique. I pull out base and individual styles for each element included in each section:</p><pre>partials<br>├── section<br>│   ├── style.html<br>│   ├── base.html<br>├── elements<br>│   ├── element<br>│   │   ├── style.html<br>│   │   ├── base.html</pre><p>This method allows for some pretty cool stuff, such as overlaying a visual builder that generates the front-matter required to build each partial layout.</p><p>Follow me on Twitter: <a href="https://twitter.com/BenBozzay">https://twitter.com/BenBozzay</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=48c52c2d8f82" width="1" height="1" alt=""><hr><p><a href="https://blog.fullstackdigital.com/how-to-automatically-generate-and-inline-critical-css-with-hugo-pipes-48c52c2d8f82">How to Automatically Generate and Inline Critical CSS with Hugo Pipes</a> was originally published in <a href="https://blog.fullstackdigital.com">Fullstack Digital</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Increase Search Traffic for a Low Rated Website in 2018]]></title>
            <link>https://blog.fullstackdigital.com/how-to-increase-search-traffic-for-a-low-rated-website-in-2018-11b47a57ab59?source=rss----9b1e3bc24b6e---4</link>
            <guid isPermaLink="false">https://medium.com/p/11b47a57ab59</guid>
            <category><![CDATA[link-building]]></category>
            <category><![CDATA[rankbrain]]></category>
            <category><![CDATA[backlink]]></category>
            <category><![CDATA[seo]]></category>
            <category><![CDATA[search-engine-marketing]]></category>
            <dc:creator><![CDATA[Ben Bozzay]]></dc:creator>
            <pubDate>Wed, 24 Oct 2018 18:53:44 GMT</pubDate>
            <atom:updated>2020-09-04T17:18:04.209Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*b9JY41G-pEQHlhB5MRte_g.jpeg" /></figure><p>If your website has poor domain authority due to lack of backlinks, it may seem impossible to attract any significant traffic from search engines like Google. If you’re launching a new website or trying to get more out of your current low-rated website, your strategy does not necessarily need to depend on link building.</p><p>This year, we overhauled the SEO of a poor performing website that had been around for several years. The website had 17 articles with a good mix of long-form content, <strong>but it had no backlinks</strong>.</p><p>Initially, it might seem like the problem was a lack of link-building. However, in just 3 months, we grew organic traffic by over <strong>400%</strong> — from 450 to 2300/month — <strong>without any link building or adding any additional content</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*yO77pbc64gmuDTZs8Sij9w.jpeg" /></figure><p>Instead of focusing on link building, we re-worked the website to focus on what Google prefers in 2018.</p><h3>Google’s AI looks for UX indicators</h3><p><a href="https://backlinko.com/google-rankbrain-seo">RankBrain</a> is Google’s automated approach to adjusting search results based on user behavior.</p><figure><a href="https://backlinko.com/google-rankbrain-seo"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uJORHv985Kadmjj1Mt-2cA.png" /></a><figcaption>Source: <a href="https://backlinko.com/google-rankbrain-seo">Backlinko</a></figcaption></figure><p>RankBrain focuses on how users interact with the results and adjusts the ranking of content that provides the best user experience.</p><p><strong>It’s one of the main reasons that it’s possible to rank for content without backlinks.</strong> RankBrain adjusts the necessity for backlinks depending on the keywords a page is optimized for.</p><p>In our situation, we noticed a large gap in useful content on the SERPs for keywords we wanted to rank for. Using a <a href="https://www.fullstory.com/">user experience tool</a> called Fullstory, we also saw a clear need to overhaul the existing content on the website.</p><h4>Bounce rate due to UX issues and relevancy</h4><p>Google analytics allows us to see the time on page and bounce rate for most users, so we could clearly see that some content either <strong>didn’t match the search intent</strong> (explained later in this article), or it wasn’t useful to the user.</p><p>We used Fullstory to watch session replays (literally watching someone read the content) so that we could see where a user lost interest. These observations helped us identify poor performing content.</p><h4>Meta descriptions should appeal to the <em>right</em> user</h4><p>The existing meta descriptions were over-optimized for keywords and not particularly appealing to humans, which probably lead to a low click through rate. Meta descriptions should focus on appealing to the user the page is positioned for.</p><h4>Topic and keyword research</h4><p>After taking an initial topic and breaking it down into a keyword matrix, we were able to generate a list of new focus keywords and topics that would appeal to the target audience. Then, we adjusted the existing information architecture to use the SEO silo approach.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/651/0*PHDl5-NBd1tSDkMK.jpg" /><figcaption>Silo example: <a href="https://webris.org/how-to-create-website-silos-for-seo/">Source</a></figcaption></figure><p>In short, it’s important to create content focused on specific topics, group that content, and then link between <strong>related content</strong>. Identifying content gaps for specific search terms allowed us to find better focus keywords and <strong>semantically related keywords</strong> that we could rank for without backlinks.</p><h4>Targeting based on intent</h4><p>Keyword research and content strategy should always examine the SERPs for a specific search term. Modern search engines personalize results by various factors like location and device (mobile/desktop).</p><p>However, <strong>Google serves different <em>types</em> of personalized search results based on search intent.</strong></p><p>A search phrase like “buy running shoes” usually displays results for nearby stores based on the user’s location.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nH5PwBUTHLF-QW8UaOUxiw.png" /></figure><p>While a search phrase like “best laptops 2018” yields different types of results — mostly websites that compare recently released laptops.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/785/1*xfqA0qBklmZWDJY24WFnHQ.png" /></figure><h3>Modern technical SEO isn’t just about robots</h3><p>Technical SEO used to focus almost entirely on how search engines could understand a website. In 2018, technical SEO also includes user experience factors.</p><h4>Websites need to be leaner, not just faster</h4><p>Google prioritizes fast, mobile-friendly websites in the search results because those websites offer a better user experience.</p><p>The wide availability of high-speed internet means that most users are able to quickly load most websites, but Google is still pushing for websites to use lean development practices.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nK-cMYYyGrdjRzBuEppNxA.png" /><figcaption><a href="http://gs.statcounter.com/platform-market-share/desktop-mobile-tablet">Source</a></figcaption></figure><p>One reason this is so important is that most users are browsing on mobile phones on limited data plans.</p><p><strong>Google is pushing for a leaner, faster web, so it makes sense that the ranking algorithm would prioritize these leaner websites.</strong> In fact, a leaner approach is important enough to Google that they launched an Open Source initiative called AMP, which is a lean approach to developing for mobile.</p><h4>Accelerated Mobile Pages (AMP)</h4><p>AMPs are lightweight versions of your existing web pages. AMP isn’t the same as responsive design: it’s about only serving critical resources required to render the page for the mobile user.</p><p>With so many users browsing the web on phones, <strong>Google prefers AMP websites in mobile search results.</strong></p><p>In addition to the ranking benefit, mobile users are more likely to notice a search result with the AMP tag:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/650/0*6vatlcMve5UXrnMp" /></figure><p>Google doesn’t want websites to just implement responsive design frameworks, they want websites to reduce how much unnecessary “stuff” a user has to download to read a page. That’s where AMP comes in, and it’s definitely a ranking factor.</p><h4>Securing the web</h4><p>Security is a big deal in 2018 and it’s another factor Google takes into account when ranking a website. It’s one of the reasons that a SSL certificate is important.</p><p>Google directly stated that HTTPS is a “<a href="https://webmasters.googleblog.com/2014/08/https-as-ranking-signal.html">lightweight signal</a>… while we give webmasters time to switch to HTTPS.” This was back in 2015. In 3 years, HTTPS has become the standard protocol and it’s safe to say that it’s a stronger factor now.</p><p>In 2018, Google started marking websites without a SSL certificate as “not secure.”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*aRppHcVljcV8R_Yq.jpg" /></figure><p>Focusing on maintaining website security also mitigates the chances of a catastrophic SEO event: a SERP security warning and potential delisting of a website.</p><figure><a href="https://searchengineland.com/hacked-content-rise-take-seo-precautions-protect-site-240855"><img alt="" src="https://cdn-images-1.medium.com/max/571/0*MO9znym5LlJgc0Rz.jpg" /></a></figure><h3>SEO in 2019 and beyond</h3><p>As Google continues to use AI to improve search and personalize results, you can future proof your SEO efforts by focusing on user experience and content positioning.</p><p><em>Specifics regarding the case study mentioned in this article available on request. For obvious reasons, we cant make identifying information public. </em><a href="https://share.hsforms.com/1noPBBK5QS76BqkhQZeniRw1pvvj/"><em>Contact me</em></a><em> if you need help with your SEO strategy.</em></p><p><em>Follow me on Twitter: </em><a href="https://twitter.com/BenBozzay"><em>https://twitter.com/BenBozzay</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=11b47a57ab59" width="1" height="1" alt=""><hr><p><a href="https://blog.fullstackdigital.com/how-to-increase-search-traffic-for-a-low-rated-website-in-2018-11b47a57ab59">How to Increase Search Traffic for a Low Rated Website in 2018</a> was originally published in <a href="https://blog.fullstackdigital.com">Fullstack Digital</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Solving Crowdfunding Fraud with WordPress]]></title>
            <link>https://blog.fullstackdigital.com/solving-crowdfunding-fraud-with-wordpress-1d5e88501879?source=rss----9b1e3bc24b6e---4</link>
            <guid isPermaLink="false">https://medium.com/p/1d5e88501879</guid>
            <category><![CDATA[web-design]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[fundraising]]></category>
            <category><![CDATA[crowdfunding]]></category>
            <category><![CDATA[wordpress]]></category>
            <dc:creator><![CDATA[Ben Bozzay]]></dc:creator>
            <pubDate>Mon, 20 Aug 2018 19:40:13 GMT</pubDate>
            <atom:updated>2022-05-03T14:55:23.209Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QV69HJenQyxTcdvaDs6Faw.jpeg" /></figure><p>Fraud has stained the crowdfunding community in general, but has especially impacted disease-related crowdfunding campaigns.</p><p>In February, a Florida family was charged with <a href="https://blog.fullstackdigital.com/r/?url=https%3A%2F%2Fwww.usatoday.com%2Fstory%2Fnews%2Fnation%2F2018%2F02%2F02%2Fflorida-parents-charged-faking-sons-brain-cancer-money%2F302971002%2F">faking their child’s brain cancer</a> to raise financial support for bogus medical costs. In another <a href="https://blog.fullstackdigital.com/r/?url=https%3A%2F%2Fwww.statnews.com%2F2017%2F11%2F01%2Fcancer-fundraising-fraud%2F">story</a>, a woman attracted over $10,000 in donations using a false cancer claim.</p><p>When it comes to crowdfunding for disease, verifying the authenticity of the campaign is absolutely necessary. <strong>Trust and authenticity allow struggling families to raise more money from the general public.</strong></p><h3>Childhood cancer deserves better crowdfunding</h3><p>Due to lack of federal funding, the childhood cancer community relies on crowdfunding and generous support from cancer foundations like <a href="https://blog.fullstackdigital.com/r/?url=https%3A%2F%2Fawoccf.org%2F">Arms Wide Open</a>.</p><p>Generic crowdfunding platforms do not verify the legitimacy of a fundraiser until <em>after</em> it is reported as fraudulent. Transaction fees also reduce the actual amount of funds raised.</p><blockquote>A crowdfunding platform should focus on a specific niche so that the fundraisers benefit from the network effect of the platform.</blockquote><h3>Verified crowdfunding with Wordpress</h3><p>We partnered with Arms Wide Open to build a crowdfunding platform focused on the childhood cancer niche. Our #1 goal was to create a system that made it easy to only publish <strong>verified fundraisers</strong> and allow families to keep <strong>100% of the raised funds.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RSHxnZxtnxjBs0gJKTVR8Q.png" /></figure><p>For this particular project, we decided to use WordPress to power the website.</p><p>We developed a simple, multi-step submission process that helped users easily submit the required verification information along with their campaign description.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BLhloV8qx14xyPtSxGImNA.png" /></figure><p>During the campaign creation process, the user must enter in medical information that allows a volunteer to verify a child’s diagnosis.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_BSnK4MYRp-7i5i7tbjvww.png" /></figure><p>Arms Wide Open manually approves and verifies each campaign individually, so a custom submission process was critical to their needs. Once a user submits their campaign for approval, the admin can easily publish the campaign after the medical information is verified. This provided a simplified administrative process, enabling foundation volunteers to easily manage the website.</p><p>Since users have ownership over their campaign, we decided to create a simplified dashboard providing an overview of useful statistics about the user’s published campaigns such as progress towards goals, share counts, contributors and more.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RSHxnZxtnxjBs0gJKTVR8Q.png" /></figure><p>Simplifying the user dashboard to only show relevant information significantly reduced support requests and provided users with a quick snapshot of their overall fundraiser performance.</p><p>With most users typically submitting fundraisers while in a hospital on a mobile device, it was critical the entire process was simplified for mobile.</p><p>Most users were referred by Facebook, so adding a one-click login with Facebook that immediately directed to the fundraiser creation page streamlined the process for mobile users.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MsWZ7UD-ec05KEpUgvBz3g.png" /></figure><h3>Impact</h3><p>To date, <a href="https://blog.fullstackdigital.com/r/?url=https%3A%2F%2Fhelpinghandsawo.org%2F">Helping Hands</a> campaigns have raised over $450,000 for childhood cancer patients and their families. Arms Wide Open covers all transaction fees to ensure families keep 100% of any funds raised. Helping Hands is completely free and all costs are completely covered by Arms Wide Open. For every $10,000 raised, Arms Wide Open covers approximately $300 in transaction fees.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*s7y8eXKYYfyTiGmoaC1TZw.png" /></figure><p><em>Follow me on twitter </em><a href="https://blog.fullstackdigital.com/r/?url=https%3A%2F%2Ftwitter.com%2FBenBozzay">https://twitter.com/BenBozzay</a>. Check out my latest project, a <a href="https://techlockdown.com">content filter</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1d5e88501879" width="1" height="1" alt=""><hr><p><a href="https://blog.fullstackdigital.com/solving-crowdfunding-fraud-with-wordpress-1d5e88501879">Solving Crowdfunding Fraud with WordPress</a> was originally published in <a href="https://blog.fullstackdigital.com">Fullstack Digital</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to create an animated logo with SVG and CSS animations]]></title>
            <link>https://blog.fullstackdigital.com/how-to-create-an-animated-logo-with-svg-and-css-animations-dbf0802a47a1?source=rss----9b1e3bc24b6e---4</link>
            <guid isPermaLink="false">https://medium.com/p/dbf0802a47a1</guid>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[logo-design]]></category>
            <category><![CDATA[animation]]></category>
            <category><![CDATA[css]]></category>
            <category><![CDATA[branding]]></category>
            <dc:creator><![CDATA[Katherine Kato]]></dc:creator>
            <pubDate>Fri, 17 Aug 2018 15:15:15 GMT</pubDate>
            <atom:updated>2018-08-17T15:15:14.769Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*LzU_2ehRnkc3tkAhW2MZUQ.gif" /></figure><p>Thoughtful logo design requires a designer to distill the essence of a brand into shapes and colors. In an overly crowded marketplace, one of the most important features of a brand is the ability to stand out and be memorable.</p><blockquote>A successful logo is memorable and tells a compelling story about your brand without using any words</blockquote><p>Enhancing a logo through animation further sets a brand apart from the competition. An animation can elegantly expand on your brand’s story.</p><p>The <a href="https://fullstackdigital.com">Fullstack Digital</a> logo animation represents the 3 layers of services we offer: brand, web, and market.</p><p>In this tutorial I will show you how to recreate the <a href="https://fullstackdigital.com/">Fullstack Digital</a> logo using CSS animations.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*PDKI18G3f05AQqcPhQnj_A.png" /></figure><p>Let’s start with animating the furthest left SVG shape as that is what appears first in the animation. Here is the starting code for the logo:</p><pre>&lt;svg xmlns=&quot;<a href="http://www.w3.org/2000/svg">http://www.w3.org/2000/svg</a>&quot; xmlns:xlink=&quot;<a href="http://www.w3.org/1999/xlink">http://www.w3.org/1999/xlink</a>&quot; width=&quot;100%&quot; height=&quot;100%&quot; viewBox=&quot;0 0 792 519&quot;&gt;<br>  &lt;polygon class=&quot;clss-1&quot; points=&quot;265.46 519 0 385.28 151.88 0 462.25 0 265.46 519&quot;/&gt;<br>  &lt;polygon class=&quot;clss-2&quot; points=&quot;430.34 519 322.94 464.08 499.23 0 627.12 0 430.34 519&quot;/&gt;<br>  &lt;polygon class=&quot;clss-3&quot; points=&quot;595.22 519 487.76 464.08 664.1 0 792 0 595.22 519&quot;/&gt;<br>&lt;/svg&gt;</pre><p>Each polygon shape within the SVG is defined by a class, .clss-1 being the polygon on the left, .clss-2 in the center, and .clss-3 on the right.</p><h3>SVG order</h3><p>The current order of the polygon shapes within the SVG will not work as the middle and right shapes would be in front of the left shape when we need them to be behind it.</p><p>Using the z-index CSS property will not work as the <a href="https://www.w3.org/TR/2015/WD-SVG2-20150915/render.html">SVG Rendering Model</a> states. SVGs will render elements in the order as they appear, so we will need to simply rearrange the order the of the polygon shapes like so:</p><pre>...<br>  &lt;polygon class=&quot;clss-3&quot; points=&quot;595.22 519 487.76 464.08 664.1 0 792 0 595.22 519&quot;/&gt;<br>  &lt;polygon class=&quot;clss-2&quot; points=&quot;430.34 519 322.94 464.08 499.23 0 627.12 0 430.34 519&quot;/&gt;<br>  &lt;polygon class=&quot;clss-1&quot; points=&quot;265.46 519 0 385.28 151.88 0 462.25 0 265.46 519&quot;/&gt;<br>...</pre><h3>Animating the shapes</h3><p>To create the animation, we use the CSS @keyframes rule. We can then name the animation and apply the transform property. Let’s start with animating the furthest left SVG shape as that is what appears first in the animation. For instance, we will need to create an animation that causes the left SVG shape to appear from the left side.</p><p>The animation will be broken down using percentages. 0% being the start of the animation and 100% being the end. We will have the shape expand and move to the left using the transform property with translate() and scaleX() functions:</p><pre>@keyframes widthAni {<br>  0% {<br>    transform: translate(-30%, 0) scaleX(0);<br>  }<br>  20%, 75% {<br>    transform: translate(0, 0) scaleX(1);<br>  }<br>  95%, 100% {<br>    transform: translate(-30%, 0) scaleX(0);<br>  }<br>}</pre><h3>Calling the animation</h3><p>Since the left shape is defined as .clss-1, we will apply the widthAni animation to run infinitely for 4 seconds and set the transform-origin by adding this to the CSS:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/786/1*B7Pj36sPPlW9rX7yfqkITA.gif" /></figure><pre>.clss-1 {<br>  animation: widthAni 4s ease-in-out infinite;<br>  transform-origin: center right;<br>}</pre><h3>Animating the rest</h3><p>Only the left shape was animated and now all that is left is to animate the other two shapes.</p><p>Like the first one, the middle and right shape will use @keyframes rule with the transform property to animate. They will also use the opacity property during some parts of the animation to hide and appear:</p><pre>@keyframes springOut {<br>  0%, 20% {<br>    transform: translate(-21%, 0%);<br>    opacity: 0;<br>  }<br>  21% {<br>    transform: translate(-20.5%, 0%);<br>    opacity: 1;<br>  }<br>  27% {<br>    transform: translate(-4.75%, 0%);<br>    opacity: 1;<br>  }<br>  31%, 55% {<br>    transform: translate(0%, 0%);<br>    opacity: 1;<br>  }<br>  67% {<br>    transform: translate(-20.5%, 0);<br>    opacity: 1;<br>  }<br>  68%, 90%, 100% {<br>    transform: translate(-21%, 0);<br>    opacity: 0;<br>  }<br>}</pre><pre>@keyframes springOutAgain {<br>  0%, 20% {<br>    transform: translate(-41.5%, 0%);<br>    opacity: 0;<br>  }<br>  21% {<br>    transform: translate(-41%, 0%);<br>    opacity: 1;<br>  }<br>  27% {<br>    transform: translate(-9.5%, 0%);<br>    opacity: 1;<br>  }<br>  31%, 55% {<br>    transform: translate(0%, 0%);<br>    opacity: 1;<br>  }<br>  67% {<br>    transform: translate(-41%, 0%);<br>    opacity: 1;<br>  }<br>  68%, 90%, 100% {<br>    transform: translate(-41.5%, 0%);<br>    opacity: 0;<br>  }<br>}</pre><p>And apply the animation to their respective shapes. The animations play infinitely for 4 seconds:</p><pre>.clss-2 {<br>  animation: springOut 4s ease-in infinite;<br>}</pre><pre>.clss-3 {<br>  animation: springOutAgain 4s ease-in infinite;<br>}</pre><p>The animation is not infinite on the <a href="https://fullstackdigital.com">homepage of our website</a>.</p><h3>Vendor prefixes</h3><p>For simplicity, the code above does not use any vendor prefixes. You will want to include them while working with CSS animations and @keyframes. In doing so, the animation will render properly within supported browsers.</p><p>For example, the widthAni animation for .clss-1 would have vendor prefixes like this:</p><pre>@-webkit-keyframes widthAni {<br> 0% {<br>   -webkit-transform: translate(-30%, 0) scaleX(0);<br>   transform: translate(-30%, 0) scaleX(0);<br> }<br> 20%, 75% {<br>   -webkit-transform: translate(0, 0) scaleX(1);<br>   transform: translate(0, 0) scaleX(1);<br> }<br> 95%, 100% {<br>   -webkit-transform: translate(-30%, 0) scaleX(0);<br>   transform: translate(-30%, 0) scaleX(0);<br> }<br>}</pre><pre>@keyframes widthAni {<br> 0% {<br>   -webkit-transform: translate(-30%, 0) scaleX(0);<br>   transform: translate(-30%, 0) scaleX(0);<br> }<br> 20%, 75% {<br>   -webkit-transform: translate(0, 0) scaleX(1);<br>   transform: translate(0, 0) scaleX(1);<br> }<br> 95%, 100% {<br>   -webkit-transform: translate(-30%, 0) scaleX(0);<br>   transform: translate(-30%, 0) scaleX(0);<br> }<br>}</pre><h3>Conclusion</h3><p>View it live on the <a href="https://fullstackdigital.com/">Fullstack Digital</a> homepage, or check out this codepen:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Ffullstackdigital%2Fembed%2Fpreview%2FRyVWJW%3Fheight%3D600%26slug-hash%3DRyVWJW%26default-tabs%3Dcss%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Ffullstackdigital%2Fpen%2FRyVWJW&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F1954961.RyVWJW.small.d643fa73-8eaa-43ce-87ad-c91a519f3b4d.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/83a7bb92f940c9ed9aaf32cefbbd9083/href">https://medium.com/media/83a7bb92f940c9ed9aaf32cefbbd9083/href</a></iframe><p>If you’d like to easily build blazing fast websites with flawless layouts, we’re releasing a <strong>free visual website builder </strong>soon. It’s a great alternative to Wordpress.<strong> Sign up for early access below:</strong></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fupscri.be%2Fefcb11%3Fas_embed%3Dtrue&amp;dntp=1&amp;url=https%3A%2F%2Fupscri.be%2Fefcb11%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=upscri" width="800" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/14568360bba2410aac2e339538e5a069/href">https://medium.com/media/14568360bba2410aac2e339538e5a069/href</a></iframe><p><em>When I’m not writing, I’m helping businesses go further, faster at </em><a href="https://fullstackdigital.com"><em>Fullstack Digital</em></a><em>. We provide digital brand strategy, design, development, and marketing for forward-thinking companies. Check out some of our work </em><a href="https://fullstackdigital.com/work/"><em>here</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dbf0802a47a1" width="1" height="1" alt=""><hr><p><a href="https://blog.fullstackdigital.com/how-to-create-an-animated-logo-with-svg-and-css-animations-dbf0802a47a1">How to create an animated logo with SVG and CSS animations</a> was originally published in <a href="https://blog.fullstackdigital.com">Fullstack Digital</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Creating an animated dashed line background with SVG and CSS]]></title>
            <link>https://blog.fullstackdigital.com/creating-an-animated-dashed-line-background-with-svg-and-css-170f89f47000?source=rss----9b1e3bc24b6e---4</link>
            <guid isPermaLink="false">https://medium.com/p/170f89f47000</guid>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[landing-pages]]></category>
            <category><![CDATA[web-design]]></category>
            <category><![CDATA[css]]></category>
            <category><![CDATA[svg]]></category>
            <dc:creator><![CDATA[Katherine Kato]]></dc:creator>
            <pubDate>Tue, 31 Jul 2018 15:05:09 GMT</pubDate>
            <atom:updated>2019-03-05T14:34:01.045Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZcKbwb0eczb0u792UrCWwg.gif" /></figure><p>In this tutorial I will show you how to create a neat SVG background animation using CSS animation. This pattern was built for the <a href="https://twitter.com/pancakesbuilder">Pancakes Builder</a> landing page. Pancakes is an upcoming free website builder for <a href="https://gohugo.io/">Hugo</a>, a powerful static site generator.</p><figure><a href="https://bossfreelance.com"><img alt="" src="https://cdn-images-1.medium.com/max/397/1*Sm9xbsYc9rc-33cQbi6Tfw.jpeg" /></a></figure><h3>Creating the SVG</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/798/1*SeXJtK-ALkdHbXB1_xPFVw.png" /></figure><p>Start off by making a straight line with the &lt;line&gt; tag wrapped in the &lt;svg&gt; tag like this:</p><pre>&lt;svg width=&quot;100%&quot; height=&quot;100%&quot; xmlns=&quot;<a href="http://www.w3.org/2000/svg">http://www.w3.org/2000/svg</a>&quot; xmlns:xlink=&quot;<a href="http://www.w3.org/1999/xlink">http://www.w3.org/1999/xlink</a>&quot; preserveAspectRatio=&quot;xMidYMid&quot;&gt;<br>  &lt;line x1=&quot;0&quot; y1=&quot;15&quot; x2=&quot;100%&quot; y2=&quot;15&quot; /&gt;<br>&lt;/svg&gt;</pre><p>The width and height should be to 100% since the SVG will need to be stretched to fit the screen width and height. On &lt;line&gt;, the x1 and x2 values are defined as the horizontal starting and ending points of a line, while y1 and y2 are the vertical starting and ending points. The current values will create a simple, straight line that fills the screen width at 100%.</p><p>To create the dashes, we will use the stroke-dasharray property. The first value is the stroke size and the second is the space in between each dash. Let’s use CSS to define the values 66 and 16 to start like so:</p><pre>line {<br>  stroke: #f4f4f4;<br>  stroke-dasharray: 66, 16;<br>}</pre><p>Now you should have one simple dashed line. To increase the line stroke weight and give it rounded edges, you can define them with CSS:</p><pre>line {<br>  ...<br>  stroke-width: 10;<br>  stroke-linecap: round;<br>  ...<br>}</pre><p>Time to create the pattern. Adjust the code in the &lt;svg&gt;:</p><pre>&lt;svg width=&quot;100%&quot; height=&quot;100%&quot; xmlns=&quot;<a href="http://www.w3.org/2000/svg">http://www.w3.org/2000/svg</a>&quot; xmlns:xlink=&quot;<a href="http://www.w3.org/1999/xlink">http://www.w3.org/1999/xlink</a>&quot; preserveAspectRatio=&quot;xMidYMid&quot;&gt;<br>  &lt;defs&gt;<br>    &lt;pattern id=&quot;pancakes-pattern&quot; x=&quot;0&quot; y=&quot;0&quot; width=&quot;100%&quot; height=&quot;200&quot; patternUnits=&quot;userSpaceOnUse&quot;&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;15&quot; x2=&quot;100%&quot; y2=&quot;15&quot; /&gt;<br>    &lt;/pattern&gt;<br>  &lt;rect x=&quot;0&quot; y=&quot;0&quot; width=&quot;100%&quot; height=&quot;100%&quot; fill=&quot;url(#pancakes-pattern)&quot;&gt;&lt;/rect&gt;<br>&lt;/svg&gt;</pre><p>With CSS, set the height of &lt;svg&gt; to 100vh. The pattern will then cover 100% of the current viewport height. However, you will notice that there are some blank space in the pattern.</p><p>At this point it is just all about calculating how much space for each &lt;line&gt; on each row by changing the y1 and y2 values. Starting from the first &lt;line&gt; having y1 and y2 values of 15, add 25 each time for each row. In this instance, the next few &lt;line&gt; tags would look like the following:</p><pre>...<br>      &lt;line x1=&quot;0&quot; y1=&quot;40&quot; x2=&quot;100%&quot; y2=&quot;40&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;65&quot; x2=&quot;100%&quot; y2=&quot;65&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;90&quot; x2=&quot;100%&quot; y2=&quot;90&quot; /&gt;<br>...</pre><p>Keep adding the values until the pattern does not have anymore blank space.</p><h3>Nesting the &lt;pattern&gt;</h3><p>To add the colored area to the pattern, the &lt;svg&gt; code is edited to be:</p><pre>&lt;svg width=&quot;100%&quot; height=&quot;100%&quot; xmlns=&quot;<a href="http://www.w3.org/2000/svg">http://www.w3.org/2000/svg</a>&quot; xmlns:xlink=&quot;<a href="http://www.w3.org/1999/xlink">http://www.w3.org/1999/xlink</a>&quot; preserveAspectRatio=&quot;xMidYMid&quot;&gt;<br>  &lt;defs&gt;<br>    &lt;pattern id=&quot;pancakes-pattern&quot; x=&quot;0&quot; y=&quot;0&quot; width=&quot;100%&quot; height=&quot;200&quot;  patternUnits=&quot;userSpaceOnUse&quot;&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;15&quot; x2=&quot;100%&quot; y2=&quot;15&quot; /&gt;<br>      ...<br>      &lt;line x1=&quot;0&quot; y1=&quot;215&quot; x2=&quot;100%&quot; y2=&quot;215&quot; /&gt;<br>    &lt;/pattern&gt;<br>    &lt;pattern id=&quot;logo&quot; x=&quot;0&quot; y=&quot;0&quot; width=&quot;100%&quot; height=&quot;200&quot; patternUnits=&quot;userSpaceOnUse&quot;&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;15&quot; x2=&quot;100%&quot; y2=&quot;15&quot; /&gt;<br>      ...<br>      &lt;line x1=&quot;0&quot; y1=&quot;215&quot; x2=&quot;100%&quot; y2=&quot;215&quot; /&gt;<br>    &lt;/pattern&gt;<br>  &lt;/defs&gt;<br>  &lt;rect x=&quot;0&quot; y=&quot;0&quot; width=&quot;100%&quot; height=&quot;100%&quot; fill=&quot;url(#pancakes-pattern)&quot;&gt;&lt;/rect&gt;<br>  &lt;rect x=&quot;22%&quot; y=&quot;27%&quot; width=&quot;250&quot; height=&quot;150&quot; fill=&quot;url(#logo)&quot;/&gt;<br>&lt;/svg&gt;</pre><p>And add this to the CSS:</p><pre>#logo line {<br>  stroke: #ffd05e;<br>}</pre><h3>Animating the &lt;pattern&gt;</h3><p>Using CSS animations, we can use the stroke-dashoffset property to animate the lines. First, set the &lt;line&gt; to have a value for stroke-dashoffset:</p><pre>line {<br>  ...<br>  stroke-dashoffset: 82;<br>}</pre><p>Then create a @keyframes rule and set the stroke-dashoffset to 0:</p><pre><a href="http://twitter.com/keyframes">@keyframes</a> lineMove {<br>  to {<br>    stroke-dashoffset: 0;<br>  }<br>}</pre><p>Finally, use the CSS :nth-child selector for the &lt;line&gt; tag. Define them with odd and even values and have the even value play the animation in reverse like this:</p><pre>line:nth-child(odd) {<br>  animation: lineMove 2s infinite linear;<br>}</pre><pre>line:nth-child(even) {<br>  animation: lineMove 2s infinite linear reverse;<br>}</pre><h3>Wrapping Up</h3><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Ffullstackdigital%2Fembed%2Fpreview%2FKBZbKr%3Fheight%3D600%26slug-hash%3DKBZbKr%26default-tabs%3Dhtml%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Ffullstackdigital%2Fpen%2FKBZbKr&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fm.cdpn.io%2Fscreenshot-coming-soon-small.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/24a7ea8b734052d3fd6fb23f2bd33718/href">https://medium.com/media/24a7ea8b734052d3fd6fb23f2bd33718/href</a></iframe><p>Here is how the SVG code should look when completed:</p><pre>&lt;svg width=&quot;100%&quot; height=&quot;100%&quot; xmlns=&quot;<a href="http://www.w3.org/2000/svg">http://www.w3.org/2000/svg</a>&quot; xmlns:xlink=&quot;<a href="http://www.w3.org/1999/xlink">http://www.w3.org/1999/xlink</a>&quot; preserveAspectRatio=&quot;xMidYMid&quot;&gt;<br>  &lt;defs&gt;<br>    &lt;pattern id=&quot;pancakes-pattern&quot; x=&quot;0&quot; y=&quot;0&quot; width=&quot;100%&quot; height=&quot;200&quot; patternUnits=&quot;userSpaceOnUse&quot;&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;15&quot; x2=&quot;100%&quot; y2=&quot;15&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;40&quot; x2=&quot;100%&quot; y2=&quot;40&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;65&quot; x2=&quot;100%&quot; y2=&quot;65&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;90&quot; x2=&quot;100%&quot; y2=&quot;90&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;115&quot; x2=&quot;100%&quot; y2=&quot;115&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;140&quot; x2=&quot;100%&quot; y2=&quot;140&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;165&quot; x2=&quot;100%&quot; y2=&quot;165&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;190&quot; x2=&quot;100%&quot; y2=&quot;190&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;215&quot; x2=&quot;100%&quot; y2=&quot;215&quot; /&gt;<br>    &lt;/pattern&gt;<br>    &lt;pattern id=&quot;logo&quot; x=&quot;0&quot; y=&quot;0&quot; width=&quot;100%&quot; height=&quot;200&quot; patternUnits=&quot;userSpaceOnUse&quot;&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;15&quot; x2=&quot;100%&quot; y2=&quot;15&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;40&quot; x2=&quot;100%&quot; y2=&quot;40&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;65&quot; x2=&quot;100%&quot; y2=&quot;65&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;90&quot; x2=&quot;100%&quot; y2=&quot;90&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;115&quot; x2=&quot;100%&quot; y2=&quot;115&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;140&quot; x2=&quot;100%&quot; y2=&quot;140&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;165&quot; x2=&quot;100%&quot; y2=&quot;165&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;190&quot; x2=&quot;100%&quot; y2=&quot;190&quot; /&gt;<br>      &lt;line x1=&quot;0&quot; y1=&quot;215&quot; x2=&quot;100%&quot; y2=&quot;215&quot; /&gt;<br>    &lt;/pattern&gt;<br>  &lt;/defs&gt;<br>  &lt;rect x=&quot;0&quot; y=&quot;0&quot; width=&quot;100%&quot; height=&quot;100%&quot; fill=&quot;url(#pancakes-pattern)&quot;&gt;&lt;/rect&gt;<br>  &lt;rect x=&quot;22%&quot; y=&quot;27%&quot; width=&quot;250&quot; height=&quot;150&quot; fill=&quot;url(#logo)&quot;/&gt;<br>&lt;/svg&gt;</pre><p>And the CSS:</p><pre>svg {<br>  height: 100vh;<br>}</pre><pre>line {<br>  stroke: #f4f4f4;<br>  stroke-width: 10;<br>  stroke-linecap: round;<br>  stroke-dasharray: 66, 16;<br>  stroke-dashoffset: 82;<br>}</pre><pre>line:nth-child(odd) {<br>  animation: lineMove 2s infinite linear;<br>}</pre><pre>line:nth-child(even) {<br>  animation: lineMove 2s infinite linear reverse;<br>}</pre><pre>#logo line {<br>  stroke: #ffd05e;<br>}</pre><pre><a href="http://twitter.com/keyframes">@keyframes</a> lineMove {<br>  to {<br>    stroke-dashoffset: 0;<br>  }<br>}</pre><p>That’s it! This is my first article here on Medium and I wanted to share my process on how I made this SVG line animation background. Referencing the <a href="https://developer.mozilla.org/en-US/docs/Web/SVG">MDN Web Docs</a> and <a href="http://shop.oreilly.com/product/0636920037972.do">Using SVG with CSS3 and HTML5 (O’Reilly)</a> helped me with understanding and creating this animation.</p><figure><a href="https://bossfreelance.com"><img alt="" src="https://cdn-images-1.medium.com/max/397/1*Sm9xbsYc9rc-33cQbi6Tfw.jpeg" /></a></figure><p><em>When I’m not writing, I’m helping businesses go further, faster at </em><a href="https://fullstackdigital.com"><em>Fullstack Digital</em></a><em>. We provide digital brand strategy, design, development, and marketing for forward-thinking companies. Check out some of our work </em><a href="https://fullstackdigital.com/work/"><em>here</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=170f89f47000" width="1" height="1" alt=""><hr><p><a href="https://blog.fullstackdigital.com/creating-an-animated-dashed-line-background-with-svg-and-css-170f89f47000">Creating an animated dashed line background with SVG and CSS</a> was originally published in <a href="https://blog.fullstackdigital.com">Fullstack Digital</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using GitHub to Sync 100 Projects on Dell's Open Source Website]]></title>
            <link>https://blog.fullstackdigital.com/how-we-automatically-synchronize-100-projects-on-dells-open-source-website-8da0c54669d4?source=rss----9b1e3bc24b6e---4</link>
            <guid isPermaLink="false">https://medium.com/p/8da0c54669d4</guid>
            <category><![CDATA[wordpress]]></category>
            <category><![CDATA[github]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[wordpress-plugins]]></category>
            <dc:creator><![CDATA[Ben Bozzay]]></dc:creator>
            <pubDate>Thu, 26 Jul 2018 21:38:15 GMT</pubDate>
            <atom:updated>2020-09-04T17:23:28.355Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*ajbdKESdFx88OIYclI35Bg.gif" /></figure><h3>Using GitHub to Sync 100 Projects on Dell’s Open Source Website</h3><p>Companies like <a href="https://www.docker.com/docker-community">Docker</a>, <a href="https://opensource.google.com/">Google</a>, and <a href="https://opensource.fb.com/">Facebook</a> contribute to the open source community by showcasing noteworthy projects. <a href="https://opensource.google.com/projects/list/featured">Google’s Open Source</a> website lists various open source projects, typically including a basic project overview, links to documentation and resources, and the main website and GitHub repository.</p><p>As part of our <a href="https://fullstackdigital.com/work/code-open-source/">web presence overhaul</a> for <a href="https://thecodeteam.com/">{code}</a>, Open Source at Dell Technologies, we transformed the way open source projects were curated and showcased on their website.</p><h3>Where we started</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bufsMVuD7_mRePZixlC6yQ.jpeg" /></figure><ol><li><strong>Updates: </strong>Showcased projects were manually added with HTML/CSS, meaning a developer was required each time a new project was added. {code} showcases hundreds of projects, so this process created a significant bottleneck.</li><li><strong>Tiles/Images: </strong>Project images had to be manually generated by a graphic designer.</li><li><strong>Search/Explore:</strong> Projects weren’t searchable and filtering options were limited to tags.</li><li><strong>Landing Pages: </strong>Projects didn’t have landing pages. {code} wanted to help projects lacking a main website by providing them with a landing page.</li></ol><h3>The result</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Vs9dFOL2q4ve6mD9mnFbug.jpeg" /></figure><ol><li><strong>Updates:</strong> Projects were now automatically imported and GitHub stats synchronized in real-time. Non-technical users could easily add projects from the WordPress dashboard.</li><li><strong>Tiles/Images:</strong> Project images were easily generated using CSS gradient backgrounds and the project logo, so a graphic designer wasn’t needed.</li><li><strong>Search/Explore: </strong>Users could now search projects and filter/sort with more options like GitHub stats.</li><li><strong>Landing Pages: </strong>Project landing pages were auto-generated and included real-time information and stat synchronization.</li></ol><p>Since no Wordpress plugins existed with this functionality, we developed our own plugin integrating Github with Wordpress.</p><h3>Synchronizing projects as Wordpress custom post types</h3><p>We decided to import Wordpress projects as custom post types in order to display projects using Wordpress queries.</p><p>In order to add a project, the admin simply needed to enter a link to the GitHub repository:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/374/0*vWDOxPxtFvbsMEBg" /></figure><p>All project information would be imported as custom fields, custom taxonomies, and content in the text editor:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*A7KyPhUNPfzc9yky" /></figure><p>Once projects are imported, the GitHub page readme file and stats are checked for changes every 15 minutes and then updated if there are any changes, thanks to the GitHub API:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/431/1*F1mfH5kLMYxAtxklrQ3mFg.gif" /></figure><p>This meant that each project always provided a real-time count of forks, contributors, and stars while importing readme file changes:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yTWutlcbQliV9YIlIN50DQ.jpeg" /><figcaption>Fully Generated &amp; Automated Project Landing Page</figcaption></figure><p>Project readme files were imported as markdown to the Wordpress text editor and we used filters to convert the markdown to HTML on the front-end. This meant the original format was maintained and didn’t require any manual formatting:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ACXjQKN8x4NSIQMy" /></figure><p>In some cases, project readme files were incomplete or lacked formatting. For these specific cases, the admin could simply override the readme import and use a manually created description instead:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/384/0*8eAA5jVYduHw8XAI" /><figcaption>Override Readme option</figcaption></figure><p>The text editor content would not be overwritten when the project information was synchronized again.</p><h3>Searching and filtering the custom post type</h3><p>We utilized customized versions of <a href="https://facetwp.com/">FacetWP</a> and <a href="https://searchwp.com/">SearchWP</a> to create an Ajax-powered project page with searching and filtering based on the imported metadata.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*lfzRNgZEHvGNcsVh" /><figcaption>Filtering by taxonomy</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*_GAFqyIPrQQt1uOf" /><figcaption>Filtering by custom fields</figcaption></figure><h3>Showcasing featured projects with an interactive 3D grid</h3><p>A static image was originally used for the community projects banner on the home page. This meant that the banner needed to be updated every time a featured project was swapped out.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*CTiq8lCa9qOQWp12" /></figure><p>We decided to replace this banner image with an interactive 3d grid to make the website feel more unique and to simplify any changes to the featured projects in that section.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*pv2fYdg_Yw3Cb93T" /></figure><p>The {code} Community and its programs now have a better way to showcase noteworthy projects in the open source community. We continued with automating the site by <a href="https://blog.fullstackdigital.com/how-to-showcase-your-community-automatically-with-wordpress-d7986308a862">creating another plugin</a> that synchronized their entire Mobilize.io online community, automatically creating pages on their website for each user.</p><p><a href="https://blog.fullstackdigital.com/how-to-showcase-your-community-automatically-with-wordpress-d7986308a862">How to showcase your community automatically with Wordpress</a></p><p><em>If you’d like to use the Github to Wordpress plugin mention in this article, contact us at </em><a href="mailto:hello@fullstackdigital.com"><em>hello@fullstackdigital.com</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8da0c54669d4" width="1" height="1" alt=""><hr><p><a href="https://blog.fullstackdigital.com/how-we-automatically-synchronize-100-projects-on-dells-open-source-website-8da0c54669d4">Using GitHub to Sync 100 Projects on Dell&#39;s Open Source Website</a> was originally published in <a href="https://blog.fullstackdigital.com">Fullstack Digital</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to showcase your community automatically with Wordpress]]></title>
            <link>https://blog.fullstackdigital.com/how-to-showcase-your-community-automatically-with-wordpress-d7986308a862?source=rss----9b1e3bc24b6e---4</link>
            <guid isPermaLink="false">https://medium.com/p/d7986308a862</guid>
            <category><![CDATA[wordpress]]></category>
            <category><![CDATA[automatic]]></category>
            <category><![CDATA[community]]></category>
            <category><![CDATA[mobilize]]></category>
            <category><![CDATA[management]]></category>
            <dc:creator><![CDATA[Allen Djal]]></dc:creator>
            <pubDate>Tue, 17 Jul 2018 17:14:26 GMT</pubDate>
            <atom:updated>2018-07-17T17:16:02.835Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-Z_ShPJDP8ql4OkG_VokPA.jpeg" /></figure><h4>Following Docker &amp; Dell Technologies to strategic &amp; automated community building</h4><p>Teams like <a href="https://www.docker.com/">Docker</a>, <a href="https://www.honeybook.com/">Honeybook</a>, <a href="https://prezi.com/">Prezi</a>, <a href="https://thecodeteam.com/">{code} by Dell Technologies</a>, and <a href="https://www.etsy.com/">Etsy</a> manage large communities of likeminded people. For those that have programs that promote industry leaders, there is one persistent question:</p><blockquote><strong><em>How do we show gratitude to our members, especially the leaders, for contributing &amp; leading the community?</em></strong></blockquote><h3><strong>Why teams showcase community members</strong></h3><p>Free swag, shoutouts, speaking slots etc. are always good. However, providing something tangible which members can refer to with pride, share with colleagues, and help advance their careers, has proven to be a meaningful solution for many of the teams mentioned above. For example, <a href="https://www.docker.com/docker-captains">Docker</a> and <a href="https://thecodeteam.com/code-catalyst/">{code} by Dell Technologies</a> have dedicated programs that promote the work and advocacy of the members/leaders, and establish an ecosystem of individuals who improve and advance their industries. They showcase these leaders on their website for <strong>three reasons</strong>:</p><ol><li><strong>Promotion &amp; Celebration:</strong> promoting them as as individuals in their respective community — based solely on their contributions. Title or Company does not matter.</li><li><strong>Camaraderie:</strong> individuals who may seem like competitors based on their respective organization affiliation are now part of the same community, all pushing for the same goal: bringing the best out of their respective community/industry.</li><li><strong>Advancement:</strong> proof of program/community participation accelerates opportunities to advance someone’s career.</li></ol><h3><strong>How to automatically display community members on a Wordpress website</strong></h3><p>There are many challenges that come with managing those communities &amp; programs and several tools that lend a hand, such as <a href="https://www.facebook.com/groups/">Facebook</a> or <a href="https://groups.google.com">Google Groups</a>, <a href="https://discordapp.com/">Discord</a>, <a href="https://www.discourse.org/">Discourse</a>, and even email marketing tools like <a href="https://mailchimp.com/">Mailchimp</a>.</p><p>Forward thinking teams, like those aforementioned, all use <a href="https://mobilize.io/">Mobilize.io</a>: a community social space, member directory and outreach center, combined. We came across this tool while working on a project, and realized its true power when it comes to communities. Using a simple WordPress plugin, you can display community members from Mobilize on your website, by group, and keep their profile information in sync! Here’s how:</p><ol><li><a href="https://mobilize.io/pricing/"><strong>Sign-up for the Mobilize.io Enterprise Plan</strong></a> — why enterprise plan? You’ll need an API key to retrieve &amp; sync your users.</li><li><a href="https://fullstackdigital.com/labs/mobilize-wordpress-plugin/#download-early-access"><strong>Install the Mobilize.io for Wordpress Plugin</strong></a> — built <a href="https://fullstackdigital.com/labs/">by us</a>, used <a href="https://thecodeteam.com/code-catalyst/">by {code}</a> and completely free!</li><li><strong>Follow </strong><a href="https://fullstackdigital.com/labs/mobilize-wordpress-plugin/"><strong>this guide</strong></a></li></ol><blockquote>Here’s what you can do with the plugin:</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/630/1*BNOf2y8M2n1hhsna5wShpQ.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/956/1*v_pX9bnghBG-mLvCyV4MMg.gif" /></figure><p><strong>Sync Data: </strong>Automatically synchronize new and inactive Mobilize community members.</p><p><strong>Make Member Profile Pages: </strong>Synchronize profile page content on a regular basis.</p><p><strong>Segment By Group:</strong> Supports groups and group-specific custom fields. Good for different types of groups like programs, communities, partners, etc.</p><p><strong>Display Anywhere: </strong>List community members using shortcodes or a standard WordPress query. Easy!</p><p><strong>Customize:</strong> Display custom fields using shortcodes with enhanced options, such as separating/ joining field values and conditional content. Good for showing any custom fields you’ve added in Mobilize.</p><h3>Looking ahead</h3><p>The evolution of community management is inspiring, and we hope that we can continue to contribute and advance it. If you’d like any help integrating this with your company/team/project website, we’re always <a href="https://fullstackdigital.com/contact/">available</a>!</p><p><em>Shoutout to </em><a href="https://medium.com/u/ee2e287cbf51">Jonas Rosland</a><em> and the rest of the (</em><a href="https://blog.thecodeteam.com/2018/02/22/final-thank-code-team/"><em>existing</em></a><em>) {code} team @ Dell Tech for their collaboration with Fullstack on this project. Disclaimer: We’re not partnered with or affiliated with Mobilize.io, nor is this post sponsored by them.</em></p><p><em>When I’m not writing, I’m helping businesses go further, faster at </em><a href="https://fullstackdigital.com"><em>Fullstack Digital</em></a><em>. We provide digital brand strategy, design, development, and marketing for forward-thinking companies. Check out some of our work </em><a href="https://fullstackdigital.com/work/"><em>here</em></a><em>.</em></p><p><em>Follow me on twitter </em><a href="https://twitter.com/allendjal"><em>https://twitter.com/allendjal</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d7986308a862" width="1" height="1" alt=""><hr><p><a href="https://blog.fullstackdigital.com/how-to-showcase-your-community-automatically-with-wordpress-d7986308a862">How to showcase your community automatically with Wordpress</a> was originally published in <a href="https://blog.fullstackdigital.com">Fullstack Digital</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>