Categories
Uncategorized

Adding async/defer to WordPress site

WordPress doesn’t add async or defer attributes to scripts by default and there is no easy way to do it without customization. This post will discuss how to add the attributes and why it’s important.

This gets complicated by the fact that not all scripts need to have defer or async either because they were moved to the footer, or because it already has the necessary one, or because of special requirements. So there is no one size fits all solution.

WordPress script_loader_tag hook allows us to tweak individual script tags to add attributes or other items before they are printed to the page.

In this example, we add the defer attribute using the script_loader_tag.

Inside rivendellweb_js_defer_attr we do the following:

  1. Stores the script we want to add the attribute to in a variable $scripts to include
  2. For each script in $scripts to include
  3. Test if the script to include matches the script we’re currently processing
    • If it does, then replace it with a version containing the defer attribute
  4. If it doesn’t the if statement will end and we’ll return the script without changes.
function rivendellweb_js_defer_attr($tag){

    // List scripts to work with
    $scripts_to_include = array(
      'hoverintent-js.min.js',
      'lazy-images.min.js'); // 1

    foreach($scripts_to_include as $include_script) { // 2
        if(true == strpos($tag, $include_script )) // 3
        // Add defer attribute
        return str_replace( ' src', ' defer src', $tag ); 
    }

    # Return original tag for all scripts not included
    return $tag; // 4

}
add_filter( 'script_loader_tag', 'rivendellweb_js_defer_attr', 10 );

The add_filter function takes two parameters: The filter hook that we want to operate on and a function detailing what we want to do, in this case, rivendellweb_js_defer_attr.

Categories
Uncategorized

PostCSS deep dive

PostCSS is an interesting tool and ecosystem. It is a CSS processor written in Javascript.

What first brought my attention to PostCSS is Autoprefixer, my go-to tool for automating adding prefixes to my CSS. A few years ago they moved from a separate project into a PostCSS plugin.

However, it wasn’t until recently that I started looking at the original purpose of PostCSS, to be able to write future CSS for today’s browsers.

The goals of the research seek to answer the following questions:

  • Can we replace SCSS with CSS using PostCSS plugins?
  • How can we leverage new CSS features in our existing stylesheets?
  • Is it worth using Javascript to do this?

For this experiment I will use the following plugins:

  • css-preset-env
  • Autoprefixer
  • CSS Nano

I will also use Gulp as my build system. It’s what I’m already using and I won’t consider any solution that doesn’t allow me to leverage it.

Getting things started

The first step is to configure the repository, if you haven’t done so already, using these commands:

git init #1
npx license $(npm get init.license) \
  -o "$(npm get init.author.name)" > LICENSE #2
npx gitignore node #3
npm init -y #4
  1. Initializes an empty Git repository
  2. Uses the license NPM package through NPX to create an MIT LICENSE file (MIT is the default license for my projects)
  3. Uses the gitignore NPM package to create a Node-based exclusion file
  4. Creates an empty package.json file accepting all default values

Installing the packages

Once we have configured the project we can install the packages we will use:

npm install --save gulp \
  postcss \
  autoprefixer \
  postcss-preset-env \
  cssnano

If you are integrating this experiment into an existing project then whatever packages are already installed they will be updated.

Once we install the packages we need to create a gulpfile.js file where we’ll write the tasks to test the plugins.

The Gulpfile

We first require Gulp, gulp-postcss (to make Gulp and PostCSS work together), and the PostCSS plugins that we want to use.

This is a very small sample of the PostCSS plugins available.

const gulp = require('gulp');
const postcss = require('gulp-postcss');
const postcssPresetEnv = require('postcss-preset-env');
const sorting = require('postcss-sorting');
const autoprefixer = require('autoprefixer');
const nano = require('cssnano');

The following sections represent different portions of a single Gulp task. It has been broken down for easy of explaining.

First, we run the code through postcss-preset-env, a CSS version of Babel, to convert the CSS we enter into CSS that is usable by our target browsers.

It uses the list of features identified at stage 3 from cssdb and additionally it will transform nested rules.

It is tempting to use stage 2 features from the database but until a feature reaches stage 3 in the database it is still subject to change and these changes can be substantial.

gulp.task('css', () => {
  return gulp.src('./src/*.css').pipe(
    postcss([
      postcssPresetEnv({
        stage: 3,
        features: {
          'nesting-rules': true
        }
      }),

Once we have CSS that will work, we run it through postcss-sorting to group content inside rules according to set criteria.

The plugins:

  • Sorts rules and at-rules content.
  • Sorts properties.
  • Sorts at-rules by different options.
  • Groups properties, custom properties, nested rules, nested at-rules.

I do this rather than sort them alphabetically because it’s easier to reason what selectors do when I can see all the rules for specific functionality grouped together.

      sorting({
        'order': [
          'custom-properties',
          'at-rules',
          'declarations',
          'rules'
        ],
        "properties-order": [
          "font",
          "color",
          "margin",
          "padding",
          "border",
          "background"
        ],
        'unspecified-properties-position': 'bottom'
      }),

The final steps are to run the stylesheet through Autoprefixer and CSS Nano

Autoprefixer saves us from having to manually enter prefixes for the rules that need it, based on the browsers we support.

CSS Nano is a CSS minimizer. It uses multiple strategies to make the resulting stylesheets as small as possible.

      autoprefixer(/* no options needed*/),
      nano(/* no options needed*/)
    ])
  )

It does an awesome job but it may go too far. I’ll explain why I think so in the evaluation at the end of the post.

The final step in the task is to pipe the stream to its final destination. Now we’re done with the styling.

  .pipe(
    gulp.dest('./dist/css')
  )
});

Modifying package.json

PostCSS and its ecosystem rely on browserslist to provide a list of supported browsers.

The best way to do it is to integrate it on your project’s package.json file. To do so add the following block to your package.json file.

"browserslist": [
  "last 3 versions",
  "> 0.2%",
  "not IE 11",
  "not IE_Mob 11",
  "not dead"
],

Doublechecking your work

To make sure that your list of supported browsers works as intended you can use tools like browserl.ist to validate that it works and that it returns the browsers you want.

In theory, running npx browserslist would also validate the browserslist section of package.json but I’ve been unable to make it work.

Evaluation: Yes, no, maybe?

PostCSS eliminates the need for node-sass and the dependency on specific versions of Node for specific versions of SASS.

However, there are way too many tools that do essentially the same thing differently based on the creator’s preference. That gets confusing as to what plugin to use to accomplish a goal.

Of the plugins, I selected to test they all work fine with some exceptions where, in my opinion, the tool is too good for what it tries to do.

If I expand a minimized stylesheet I would like to know that the original used a calc value instead of a fixed one.

For example, the following code:

.box {
    width: calc(2 * 100px);
}

Gets transformed into the code below, according to the CSS Nano documentation.

.box {
    width: 200px;
}

It is impossible to tell what code resulted in the code shown in the docs. This doesn’t matter if you have the source stylesheets but it’s important if you’re trying to reason through someone’s code (and I still think this is an important thing to do).

As long as we’re ok with that kind of aggressive minimization then the tool does what it’s meant to and we’re good to go.

If we’re not OK with those minimizations we need to figure out how to remove them or find another minimizer that we can configure to our liking.

Categories
Uncategorized

My VSCode Snippets

I love Visual Studio Code for writing anything ranging from Markdown to Javascript to PHP and even some Go and C/C++.

One of the things that intrigued me the most is snippets and how they work once you insert them.

The following example shows a VS Code snippet that will insert a figure with img and figcaption children.

The elements in the JSON for the snippet are:

  • scope: What language or languages the snippet applies to
  • prefix: The short name for the snippet
  • body: The content for the snippet, including placeholders
  • description:
{
    "HTML figure": {
        "scope": "html, markdown",
        "prefix": "fig",
        "body": [
            "<figure>",
            "  <img loading='lazy' src='$1' alt='${2:alt text}' width='${3:width}' height='${4:height}'>",
            "  <figcaption>'${5:caption text}'</figcaption>",
            "</figure>"
        ],
        "description": "figure element in markup/down"
    },

Inside the template, we can use placeholders on their own ($1) or placeholders with descriptive text (${2:alt text}) If more than one placeholder has the same number they will change at the same time and get the same text entered.

If you have many items that are similar and where there are small changes between the different types, you can use a snippet to handle the variance.

I use three different types of message boxes: info, warning, and danger. They all share the same code except for the second class attribute.

In the message, box snippet accepts 2 parameters, the type of box it is and the body of the box.

    "<message box": {
        "prefix": "message",
        "scope": "html, markdown",
        "body": [
            "<div class='message ${1:type of box'>",
            "  ${2:content here}",
            "</div>"
        ],
        "description": "message box: info, warning, danger"
    }
}

The last type of snippet I find useful is what I call the compound one. I use Description List a lot in my writing but I’m never quite sure of how many items I want the list to have. So, rather than create one huge DL snippet I created two.

The first snippet creates the list itself and the first item.

The second snippet creates a list item on its own

  "Def List": {
      "prefix": "dllist",
        "scope": "html, markdown",
        "body": [
            "<dl>",
            "  <dt>${1:term to define}</dt>",
            "  <dd>${2:definition of the term}",
            "</dl>"
        ],
        "description": "Definition List and First Item"
    },
    "Def List Item": {
        "prefix": "dlitem",
        "scope": "html, markdown",
        "body": [
            "  <dt>${1:term to define}</dt>",
            "  <dd>${2:definition of the term}</dd>"
        ],
        "description": "Individual DL item"
    }
}

You can build more complex snippets for whatever language you need. It is nice to have them, particularly when you know how to use them 🙂

Check out VS Code’s Snippets in Visual Studio Code

Categories
Uncategorized

SVG and CSS for cool effects with text

In recent years there has been a lot of new features that make magazine-style layouts possible and enticing for designers to use and for developers to implement.

Some of these features are quite old in terms of when they were introduced but it wasn’t until I saw the work of Jenn Simmons, Jason Pamental and Andy Clarke that I started seeing the real possibilities of doing design on the web.

Sure we’re still missing fragmentation primitives for the web and the purists seem to have won, so far. Regions are dead and no alternatives have surfaced yet.

Clip-path

Clipping an image means that we hide parts of the images from view while showing others.

The following example will create a circle clipping area 100px in diameter around whatever image we add the class to.

.clipped {
  clip-path: circle(90px);
}

This is equivalent to the following code that you may see in some examples.

.clipped {
  clip-path: circle(90px at center center);
}

The second version of the code allows for more flexibility as we can move the center from which we generate the clipping path to create interesting variations on a theme.

For example, using portraits of presenters at a meetup, we can play with the direction of the clip to create more interesting clip effects.

Furthermore, we can define clip paths with SVG (and the full power it gives us), like the example below that will place circles in different places of the image.

<svg width="0" height="0">
  <defs>
    <clipPath id="bubbles">
      <circle cx="200" cy="100" r="40" />
      <circle cx="300" cy="60" r="40" />
      <circle cx="490" cy="50" r="40" />
      <circle cx="380" cy="140" r="40" />
      <circle cx="220" cy="220" r="40" />
    </clipPath>
  </defs>
</svg>

And reference the clipPath SVG element from CSS like so:

.clipped {
  clip-path: url('#bubbles');
}

An easy way to create clip-path values for clipping is to use Bennet Feely’s Clippy.

Mask

Masking is, from my perspective, far more complex than clipping. According to Sarah Drasner’s Masking vs. Clipping: When to Use Each:

Think about masking as a way to apply complex, detailed, and shapes with varying opacity over another element. This can lead to really beautiful visual effects and performant alternatives to other techniques.

And according to Chris Collier’s Practical SVG:

Clipping and masking are related concepts because they are both capable of hiding parts of an image. But the distinction between them can be confusing, so let’s clear that up right now:

Clipping is created from vector paths. Anything outside the path is hidden; anything inside is shown.

Masking is created from images. Black parts of the image mask hide; white parts show through. Shades of gray force partial transparency—imagine a black-to-white gradient over an image that “fades out” the image.

Using SVG makes it easier to create masks that we can use in an HTML document.

The first SVG document creates the definitions of the elements we want to use inside a defs to hold templates for the things we want to use inside symbols

<div class="wrapper">
  <svg width="200" height="300">
    <defs>
      <symbol id="s-mask-circles">
        <g stroke="lightgrey" stroke-width="10" fill="white">
          <circle cx="125px" cy="30%" r="20%" />
          <circle cx="52%" cy="62%" r="32%" />
        </g>
      </symbol>

      <symbol id="illiad">
        <image xlink:href="images/Illiad1-mod.jpg" width="398" height="300" />
      </symbol>

      <symbol id="coffee">
        <image xlink:href="images/coffee2.png" width="199" height="375" />
      </symbol>

      <mask id="mask-circles">
        <use xlink:href="#s-mask-circles" />
      </mask>
    </defs>

  </svg>

We can then use additional SVG elements to create the masks. The examples below use the elements we defined earlier in the mask and use elements.

<svg width="200" height="300">
  <g mask="url(#mask-circles)">
    <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#illiad"></use>
  </g>
</svg>

<svg width="200" height="300">
  <g mask="url(#mask-circles)">
    <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#coffee"></use>
  </g>
</svg>

This works with SVG elements and the flexibility they give you is amazing. But it doesn’t work with CSS directly.

Using masks in CSS is a two-step process.

  1. Create the mask image using a tool like Photoshop or GIMP
  2. Use the mask image as the attribute for the mask-image attribute
  3. Use the mask-type attribute to indicate what type of mask you want to use

In the HTML document, we provide the background image for our experiment.

<img src="images/chile-01.jpg">

The CSS does a few things:

  1. It says the image to display-block just to make sure in case we set it to something else in the stylesheet
  2. Set mask-image to the image that we want to set as the mask
  3. Position the mask image using mask-position
  4. Choose if we want to repeat the mask image using mask-repeat
img {
  margin: 20vh auto;
  display: block; /* 1 */
  width: 50%;
  height: 400px;
  -webkit-mask-image:
    url(images/mask-image.png); /* 2 */
  mask-image:
    url(images/mask-image.png); /* 2 */
  -webkit-mask-position: center bottom; /* 3 */
  mask-position: center bottom; /* 3 */
  -webkit-mask-repeat: no-repeat; /* 4 */
  mask-repeat: no-repeat; /* 4 */
}

Right now we have to duplicate code for the mask attributes because Blink supports only prefixed versions of the attributes but we still want to future proof our code. Tools like Autoprefixer or Prefix Free will keep our code DRY.

In the video CJ Gammon, from Adobe, presents a deep dive on masking, which may be easier to process.

Motion on a path

Motion on a path is interesting. It allows you to create animations that follow a set path (defined using SVG path elements).

The three important aspects of this code:

  1. offset-path sets the path we want the animation to navigate
  2. The animation
  3. We create the steps of the animation using the @keyframes at-rule. Make sure the name matches the one we used in the animation rule
#motion-demo {
  offset-path: path('M6,150C49.63,93,105.79,36.65,156.2,47.55,207.89,58.74,213,131.91,264,150c40.67,14.43,108.57-6.91,229-145'); /* 1 */
  animation: move 4000ms infinite alternate ease-in-out; /* 2 */
  width: 40px;
  height: 40px;
  background: rebeccapurple;
}

@keyframes move { /* 3 */
  0% {
    offset-distance: 0%;
  }
  100% {
    offset-distance: 100%;
  }
}

Text on a path

We can also do text on a path using SVG paths, text, and textPath elements.

<svg viewBox="0 0 425 300">
  <path id="curve"
      d="M6,150C49.63,93,105.79,36.65,156.2,47.55,207.89,58.74,213,131.91,264,150c40.67,14.43,108.57-6.91,229-145" />
  <text x="25">
    <textPath xlink:href="#curve">
      Dangerous Curves Ahead
    </textPath>
  </text>
</svg>

There are ways to animate the text as it moves on the path we’ve set up. Sadly it’s an all-SVG solution right now.

<svg id="canvas" xmlns="http://www.w3.org/2000/svg" version="1.1" width="800px" height="800px" preserveAspectRatio="none"> <!-- 1 -->
  <defs>
    <path id="curve" d="
          M 400, 200
          a100,100 0 1,1 0,-.00001 z"
          fill="none"
          stroke="transparent"
          stroke-width="1"></path> <!-- 2 -->
  </defs>
  <text dx="50"
        font-family="Verdana"
        font-size="18"
        fill="rebeccapurple"> <!-- 3 -->
      <textPath
        xlink:href="#curve">Hello, here is some text animated along a crazy path.</textPath> <!-- 4 -->
      <animate
        attributeName="dx"
        type="xml"
        dur="12s"
        from="20"
        to="900"
        repeatCount="indefinite" /> <!-- 5 -->
  </text>
</svg>

The example does the following:

  1. Set up the SVG documents with the correct namespaces and
  2. Under defs we set up a path that the text will navigate on
  3. Set up a text element containing the text path and the associated animation
  4. Set up the content for the text we want to animate. The link to the path defined in step 2 associates the text with the path that
  5. We use a SMIL animate tag to generate the animation

This last bit is important. I’m not 100% sure if the animate element uses SMIL or not but we should move it to CSS or Web Animation API to make sure that it will continue to work after SMIL is removed from browsers.

Chris Coyier’s CSS Tricks Screencast “Three Ways to Animate SVG” covers different ways to do animated SVGs

If nothing else works, you can always pull out the big guns and use animation libraries like GSAP to animate your SVG. See Sarah Drasner’s SVG Animations for more information.

Blend Modes

One of the first things that attracted me to typography and the expressive potential of the web was seeing text with a background image bleeding through inside the shape of the letters

I later learned that technique is called blend modes and the one, in particular, I was interested in is called mix-blend-mode and there are 16 different possibilities:

  • color
  • color-burn
  • color-dodge
  • darken
  • difference
  • exclusion
  • hard-light
  • hue
  • lighten
  • luminosity
  • multiply
  • normal
  • overlay
  • saturation
  • screen
  • soft-light

See MDN’s Blend Mode for a description of what the different blend mode values do.

The basic mix blend looks like this.

h1 {
  margin: 0;
  font-size: 20vw;
  text-transform: uppercase;
  font-family: Montserrat, sans-serif;
  line-height: 1.2;
}

.blended {
  background-image:
    url(../images/tea-ceremony.jpg);
  background-position: 50% 50%;
}

.blended h1 {
  color: #000;
  background: #fff;
  font-size: 19vw;
  mix-blend-mode: lighten;
}

The markup for the blending is as simple as possible. We use a div for the background image and the text we want to blend it with

<div class="blended">
  <h1>Ichi-Go Ichi-E</h1>
</div>

The second type of blending we can do is background blending. In this example, we take one or more background images, gradients, or solid colors and blend them together.

The second example, taken from Codrops background-blend-mode page mixes two background images and a single color to create a very interesting effect.

The important part is that we can have any number of background images, colors or gradients and any number of blend modes to create whatever effects we can imagine.

.backgrounder2 {
  width: 600px;
  height: 400px;

  background-image:
    url(images/blend-mode-texture.jpg),
    url(images/blend-mode-image.jpg);
  background-color: olive;
  background-blend-mode: hard-light;
}

One final thing when talking about blend modes is that we can use gradients as background images to blend.

In the next example, we swap one of the images with a linear gradient to blend the image with, taking advantage of everything we can do with gradients.

.backgrounder3 {
  width: 600px;
  height: 400px;

  background-image:
    linear-gradient(to right, #69B62F, #DE3375),
    url(images/blend-mode-example-texture.jpg);
  background-blend-mode: hard-light;
}

Blend modes give us one more tool in the battle for creative layouts on the web.

z-index

z-index controls the stacking order of elements that share the same parent. For people looking at the screen elements with a higher z-index value will appear on top, or over, other elements without z-index.

z-index will only work on positioned elements. Even if you give an element a z-index value, it will not affect the element unless it is positioned; i.e. unless it has a position value other than the default static.

This figure illustrates the stacking order of different elements.

Stacking order when using z-index and other elements
Stacking order when using z-index and other elements

This example uses the following HTML:

<div class="container">
  <div class="image">
    <img
      src='image/chile-02.jpg'
      alt='Easter Island, Chile'>
  </div>
  <h1>Easter Island</h1>
</div>

And the accompanying CSS

.container {
  position: absolute;
}

.image {
  position: relative;
  z-index: 0;
  width: 100%;
}

.text {
  position: absolute;
  z-index: 10;
  width: 100vw;
  color: white;
  font-family: cursive;
  font-size: 8vw;
  left: 500px;
  top: 800px
}

To stack the text on top of the image to give the impression that the text is laid on top. Because we’re using positioned content we can play with left, top and z-index to create combinations of positioned text.

Final Notes: This is a nice to have

One final thing to remember is that, for all the cool things you can do with the techniques in this post, in the end, they are icing on the cake.

Where possible, and assuming that your target browsers support it, use feature queries, the @support at-rule.

This way you can provide two branches of code based on the support for a feature or the lack thereof.

As an example, this code will only use the code for #motion-demo if the browser supports either the prefixed or unprefixed versions of clip-path

@supports (clip-path: polygon(0 0)) or (-webkit-clip-path: polygon(0 0)) {
  #motion-demo {
    offset-path: path('M6,150C49.63,93,105.79,36.65,156.2,47.55,207.89,58.74,213,131.91,264,150c40.67,14.43,108.57-6.91,229-145');
    animation: move 4000ms infinite alternate ease-in-out;
    width: 40px;
    height: 40px;
    background: rebeccapurple;
  }
}

Likewise, if you use an inline SVG image to take advantage of what you can do with it, remember to provide an alternative if your target browsers don’t support the feature.

References and tools

Categories
Uncategorized

Researching Array Methods

Seeing the latest HTTP 203 from Surma and Jakke I started thinking about what other things that you can do with arrays.

The most frequent use of arrays in my code is to take an array of elements and do something to each member of the array.

For example, the following snippet converts the document.images collection into an array and then uses forEach to loop over the array, and add the loading attribute to enable native lazy loading in Chrome and provide an alternative lazy loading library for browsers that don’t support the feature natively.

if ('loading' in HTMLImageElement.prototype) {
  const myImages = [...document.images];

  myImages.forEach((myImage) => {
    myImage.setAttribute('loading', 'lazy');
  })
} else {
  console.log('native lazy loading not supported');
  // Fetch and apply a polyfill
  // for lazy-loading instead.
}

I know, if I’m creating the page from scratch it’s better to add the attribute directly to the HTML but I’m lazy and adding the attribute by hand in image/video heavy pages can take longer than inlining the script on the head of the document.

It got me thinking, what else can we do with arrays and how much would it simplify my code.

In this post, we’ll explore some things you can do with and to arrays.

Array.map

The map method creates a new array where the content is the result of applying a function to the elements in the array.

const array1 = [1, 4, 9, 16];

const map1 = array1.map(x => x * x);

console.log(map1);

Array.from

The from method creates a new, shallow-copied Array instance from an array-like or iterable object.

console.log(Array.from('foo'));

Array.every

The every method tests whether all elements in the array pass the test in the test in the associated function. It returns a Boolean value.

const isAboveThreshold = (currentValue) => currentValue > 40;

const array1 = [1, 30, 39, 29, 10, 13];

console.log(array1.every(isAboveThreshold));

Array.filter

The filter method creates a new array with all elements that pass the test in the function we pass as the parameter.

const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];

const result = words.filter(word => word.length > 6);

console.log(result);

Array.flat

The flat method creates a new array with all sub-array elements concatenated into it recursively up to the specified depth.

In the example below, play with the value for myArray.flat and see how it changes the items in the array.

const myArray = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
myArray.flat(Infinity);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Array.includes

The includes() method determines whether an array includes a certain value among its entries, returning true or false as appropriate.

Not in the example below that even though the string at appears twice in the array, array.includes returns false in the query. It appears that it’s searching for full strings, not portions of one.

const pets = ['cat', 'dog', 'bat'];
console.log(pets.includes('cat'));

console.log(pets.includes('at'));

Arrays have many other methods for you to research and play with. These are the ones I find the most useful.