Archive

Archive for August, 2021

Popular Design News of the Week: August 9 2021 – August 15, 2021

August 15th, 2021 No comments

Every day design fans submit incredible industry stories to our sister-site, Webdesigner News. Our colleagues sift through it, selecting the very best stories from the design, UX, tech, and development worlds and posting them live on the site.

The best way to keep up with the most important stories for web professionals is to subscribe to Webdesigner News or check out the site regularly. However, in case you missed a day this week, here’s a handy compilation of the top curated stories from the last seven days. Enjoy!

Dopaminite – Find the Balance Between Work and Fun

Exciting New Tools For Designers, August 2021

Atkinson Hyperlegible: A Typeface For The Visually Impaired

How to Use Pantone’s 2021 Colors of the Year in Your Designs

8 CSS Snippets for Creating Split-Screen Layouts

Reviewing the Safari redesign in iOS 15

Why it’s so Hard to Design an Olympic Logo

CSS Gradients by Baseline

Why Captcha Pictures Are So Unbearably Depressing

Things I wish I knew before switching to Figma (from Sketch)

Source

The post Popular Design News of the Week: August 9 2021 – August 15, 2021 first appeared on Webdesigner Depot.

Categories: Designing, Others Tags:

Designing UI for the Voice Era

August 13th, 2021 No comments

The world of web design is incredibly dynamic. Every year, new trends and opportunities emerge, primarily driven by the arrival of modern technology. 

In recent years, we’ve seen various updates to the web design landscape, such as the arrival of AR and VR solutions for making mixed media. Video content has increased in quality, while the demand for inclusivity and usability has transformed the way that we build everything from websites to apps. 

Yet, for the most part, web design trends have continued to focus on the visual. 

When we hear the word “interface,” we often think of the graphical user interface – the ultimate way to connect users with sites. However, now we have a new, more natural way for customers to interact with their digital tools… The era of voice is here. 

Designing for the Age of Voice

The technology sector has made incredible progress in the development of things like Automated Speech Recognition and Natural Language Understanding. 

Thanks to updates in the way that machines process and understand human language, voice recognition accuracy is now at 90% and above. More than ever before, users can speak to a smart assistant, speaker, or phone-based application, and get the results that they’re looking for without error. 

The simplicity of communicating with technology via voice means that users have adopted this technology at an incredible pace. Half of all searches will be made with voice by the end of this year.

We’re standing on the edge of a fundamental shift in the way that we interact with computers and critical tools. As designers and developers, we need to be ready to embrace this new medium. 

With that in mind, here’s what designers need to think about when designing for voice UI. 

1. Decide How to Experiment with Voice

There are various steps involved in making a website more “conversational.” One of the first steps for any designer or developer is to think about the kind of voice-based interactions they’re going to enable for an app or website. 

For instance, rather than embedding voice technology into a website, you might decide to create a separate Amazon Alexa “Skill” for devices like the Echo. Companies like Capital One have already invested in this technology so that users can ask their smart speaker about their balance, rather than opening a laptop and logging into the site. 

To determine what kind of voice experiences you should be creating for your client, work with them on a customer journey map. Using this map of interactions that the customer has with your client on a regular basis, you can highlight areas where voice interactions might fit into the user flow. 

For instance, if customers are constantly asking questions about a brand or its service, an FAQ page that’s equipped with a bot that can respond to voice queries could be an excellent choice. 

UI design should always solve problems. Examining the frictions and frustrations that your client’s end-users encounter during their journey will help you to decide which direction to take with your voice UI experience. 

2. Examine the Anatomy of Voice Commands

Before designers can create a dialog flow for their voice UI, they need to understand how voice commands work. The key to success in a successful design for voice is understanding the objective of the interaction. A voice consists of three crucial factors for designers to consider:

  • Intent: Intent represents the subject and context of the voice command. A high utility interaction involves a request for a specific task. For instance, your users might request that your app gives them a list of five-star hotels in a specific area. Designing for these requests is often straightforward because what the voice algorithm needs to do is clear. However, low-utility requests can be harder to decipher, such as “hotels near me,” because there’s less specificity for the bot to work with. 
  • Utterance: Utterance refers to how a user phrases a command. For instance, in the case of looking for five-star hotels in Amsterdam, the customer might say “show me hotels,” or they might ask for “places to stay”. Designers must consider every variation of an utterance for their voice command UI. 
  • Optional variables: This refers to the extra filters that your voice UI needs to be aware of. In the case of five-star hotels in Amsterdam, the descriptor “five stars” is optional. The optional input needs to overwrite default values and bring more detail to the search. 

SideChef, for instance, is a voice-activated recipe app that offers narrated guidance to users and allows customers to search for recipes based on their specific needs. The app comes with a wide range of variables built-in, allowing users to customize their searches according to descriptors like “vegetarian” or “quick” meals. 

3. Learn How to Prototype with Dialog Flows

Learning how to leverage a complex UI strategy like VUI takes time and practice. Prototyping designers will often have to think like scriptwriters, designing various dialog flows to suit the different needs of customers, and the numerous interactions they might face. 

Dialog flows will outline:

  • Keywords that lead to the interaction
  • Branches that represent where the conversation might lead
  • Example dialogs for the user and the voice assistant. 

Practicing your dialog flows with scripts that illustrate the back-and-forth between the voice assistant and user will help designers and developers to understand the various nuances that can appear in a customer to robot interaction. 

Remember, while a crucial part of good voice UI design is keeping the communication conversational and straightforward, you will need to ensure that there is a dialog flow in place for every discussion that may occur between end-users and their apps, website, or digital tools. Users don’t want to feel overloaded and overwhelmed, but they need to ensure that they can complete their tasks too.

Consider the voice-based game RuneScape: One Piercing Note, for instance. 

The developers behind this app allowed players to speak with other in-game characters and use commands like “pull the lever” or “open the chest.” In designing the playable components of the game, the designers needed to think about every possible interaction that a player might have with different parts of the story while ensuring that users didn’t stray off track. 

A Few Tips for Voice UI Design 

Voice UI design can be very complex, mainly if you’ve never created something using voice as your only input before. However, once you get used to creating dialog flows, the whole process starts to feel a lot easier. 

As you’re designing, remember to:

  • Always confirm when a task is complete: When designing a checkout flow for an eCommerce page, one of the most crucial screens for a designer is the confirmation page. It shows the customer that the transaction has successfully been completed and stops them from worrying whether they’ve done the right thing. The same concept applies to Voice UI design. If your client’s end-user asks a voice-activated app to book an appointment with their therapist, for instance, they want to know that the appointment has been successfully booked and added to their calendar. Determine how you’re going to deliver the peace of mind your customers need. 
  • Create a strong strategy for errors: Designers and developers are still in the very early stages of experimentation with voice UI. This means that there’s a good chance that something could go wrong with your applications and tools from time to time. Having a strong error strategy in place is crucial. Always design a dialog flow scenario that allows the assistant to respond if they don’t understand a request, or don’t hear anything at all. You can also implement analytics into these situations to identify misinterpretations and improve usability in the future.  
  • Add extra layers of security: Various Voice UI solutions like Google Assistant and Alexa can now recognize individual voices. This is a kind of biometric security that’s similar to face or touch ID. As voice recognition continues to improve, it’s essential to ensure that you’re adhering to the latest guidelines in security. Additional authentication may be required for some companies. For instance, passwords, face recognition, or fingerprints might be needed for things that require payments and transactions. For instance, the Duer voice assistant uses face recognition to both approve payments, and make meal recommendations based on previous purchases. 

Are You Ready for the Voice UI Revolution?

Voice-based user interfaces are here to stay.

In the years to come, the chances are that developers and designers will need to learn how to use voice more consistently as part of their interface strategies. 

The good news is that although voice takes some getting used to as a design tool, it’s easy enough to make sure that your projects are moving in the right direction. Just like any other kind of design, implementing voice means thinking about whether the interactions and experiences that you’re delivering to end-users are seamless, effective, and valuable. 

Succeeding in voice UI isn’t just about adding the capacity for voice into your designs. It’s a matter of learning how to make user’s lives easier with the power of voice.

 

Featured image via Unsplash.

Source

The post Designing UI for the Voice Era first appeared on Webdesigner Depot.

Categories: Designing, Others Tags:

Building a Cool Front End Thing Generator

August 13th, 2021 No comments

Whether you are just starting out on the front end, or you’ve been doing it for a long time, building a tool that can generate some cool front-end magic can help you learn something new, develop your skills and maybe even get you a little notoriety.

You might have run across some of these popular online generators:

I’ve had fun building a few of these myself over the years. Basically, any time you run across some cool front-end thing, there might be an opportunity to make an interactive generator for that thing.

In this case, we are going to make an Animated Background Gradient Generator.

Scaffolding the project in Next

A nice thing about these projects is that they’re all yours. Choose whatever stack you want and get going. I’m a big fan of Next.js, so for this project, I’m going to start as a basic Create Next App project.

npx create-next-app animated-gradient-background-generator

This generates all the files we need to get started. We can edit pages/index.js to be the shell for our project.

import Head from "next/head"
import Image from "next/image"
export default function Home() {
  return (
    <>
      <Head>
        <title>Animated CSS Gradient Background Generator</title>
        <meta name="description" content="A tool for creating animated background gradients in pure CSS." />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main>
        <h1>
          Animated CSS Gradient Background Generator
        </h1>
      </main>
    </>
  )
}

Animated gradients?

At the time I’m writing this article, if you do a search for animated CSS gradient background, the first result is this Pen by Manuel Pinto.

Let’s take a look at the CSS:

body {
  background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
  background-size: 400% 400%;
  animation: gradient 15s ease infinite;
}

@keyframes gradient {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}

This is a great example that we can use as the foundation for the generated animation.

A React component to describe an animated gradient

We can break out a few possible configurable options for the generator:

  • An array of gradient colors
  • The angle of the gradient
  • The speed of the animation

To put in context, we want to provide these settings as data throughout our little app using a higher-order component, context/SettingsContext.js, along with some defaults.

import React, { useState, createContext } from "react"

const SettingsContext = createContext({ colorSelection: [] })

const SettingsProvider = ({ children }) => {
  const [colorSelection, setColorSelection] = useState([
    "deepskyblue",
    "darkviolet",
    "blue",
  ])
  const [angle, setAngle] = useState(300)
  const [speed, setSpeed] = useState(5)
  
  return (
    <SettingsContext.Provider
      value={{
        colorSelection,
        setColorSelection,
        angle,
        setAngle,
        speed,
        setSpeed,
      }}
    >
      {children}
    </SettingsContext.Provider>
  )
}

export { SettingsContext, SettingsProvider }

For our generator’s components, we want to create:

  • a control components to adjust these settings,
  • a visual display component for generated animated gradient, and
  • a component for the CSS code output.

Let’s start with a Controls component that contains the various inputs we used to adjust the settings.

import Colors from "./Colors"

const Controls = (props) => (
  <>
    <Colors />
  </>
)

export default Controls

We can add our SettingsProvider and Controls components to pages/index.js:

import Head from "next/head"
import Image from "next/image"
import { SettingsProvider } from "../context/SettingsContext"
import Controls from "../components/Controls"
import Output from "../components/Output"

export default function Home() {
  return (
    <>
      <Head>
        ...
      </Head>

      <SettingsProvider>
        <main style={{ textAlign: "center", padding: "64px" }}>
          <h1>Animated CSS Gradient Background Generator</h1>
          <Controls />
          <Output />
        </main>
      </SettingsProvider>
    </>
  )
}

Our SettingsProvider begins with the three colors from our CodePen example as defaults. We can verify that we are getting the color settings via our SettingsContext in a new Colors component.

import React, { useContext } from "react"
import { SettingsContext } from "../context/SettingsContext"

const Colors = () => {
  const { colorSelection } = useContext(SettingsContext)
  return (
    <>
      {colorSelection.map((color) => (
        <div>{color}</div>
      ))}
    </>
  )
}

export default Colors

Let’s use the Colors component to display individual color swatches with a small button to delete via our SettingsContext.

import React, { useContext } from "react"
import { SettingsContext } from "../context/SettingsContext"

const Colors = () => {
  const { colorSelection, setColorSelection } = useContext(SettingsContext)

  const onDelete = (deleteColor) => {
    setColorSelection(colorSelection.filter((color) => color !== deleteColor))
  }

  return (
    <div>
      {colorSelection.map((color) => (
        <div
          key={color}
          style={{
            background: color,
            display: "inline-block",
            padding: "32px",
            margin: "16px",
            position: "relative",
            borderRadius: "4px",
          }}
        >
          <button
            onClick={() => onDelete(color)}
            style={{
              background: "crimson",
              color: "white",
              display: "inline-block",
              borderRadius: "50%",
              position: "absolute",
              top: "-8px",
              right: "-8px",
              border: "none",
              fontSize: "18px",
              lineHeight: 1,
              width: "24px",
              height: "24px",
              cursor: "pointer",
              boxShadow: "0 0 1px #000",
            }}
          >
            ×
          </button>
        </div>
      ))}
    </div>
  )
}

export default Colors

You may notice that we have been using inline styles for CSS at this point. Who cares! We’re having fun here, so we can do whatever floats our boats.

Handling colors

Next, we create an AddColor component with a button that opens a color picker used to add more colors to the gradient.

For the color picker, we will install react-color and use the ChromePicker option.

npm install react-color

Once again, we will utilize SettingsContext to update the gradient color selection.

import React, { useState, useContext } from "react"
import { ChromePicker } from "react-color"
import { SettingsContext } from "../context/SettingsContext"

const AddColor = () => {
  const [color, setColor] = useState("white")
  const { colorSelection, setColorSelection } = useContext(SettingsContext)

  return (
    <>
      <div style={{ display: "inline-block", paddingBottom: "32px" }}>
        <ChromePicker
          header="Pick Colors"
          color={color}
          onChange={(newColor) => {
            setColor(newColor.hex)
          }}
        />
      </div>
      <div>
        <button
          onClick={() => {
            setColorSelection([...colorSelection, color])
          }}
          style={{
            background: "royalblue",
            color: "white",
            padding: "12px 16px",
            borderRadius: "8px",
            border: "none",
            fontSize: "16px",
            cursor: "pointer",
            lineHeight: 1,
          }}
        >
          + Add Color
        </button>
      </div>
    </>
  )
}

export default AddColor

Handling angle and speed

Now that our color controls are finished, let’s add some components with range inputs for setting the angle and animation speed.

Here’s the code for AngleRange, with SpeedRange being very similar.

import React, { useContext } from "react"
import { SettingsContext } from "../context/SettingsContext"

const AngleRange = () => {
  const { angle, setAngle } = useContext(SettingsContext)

  return (
    <div style={{ padding: "32px 0", fontSize: "18px" }}>
      <label
        style={{
          display: "inline-block",
          fontWeight: "bold",
          width: "100px",
          textAlign: "right",
        }}
        htmlFor="angle"
      >
        Angle
      </label>
      <input
        type="range"
        id="angle"
        name="angle"
        min="-180"
        max="180"
        value={angle}
        onChange={(e) => {
          setAngle(e.target.value)
        }}
        style={{
          margin: "0 16px",
          width: "180px",
          position: "relative",
          top: "2px",
        }}
      />
      <span
        style={{
          fontSize: "14px",
          padding: "0 8px",
          position: "relative",
          top: "-2px",
          width: "120px",
          display: "inline-block",
        }}
      >
        {angle} degrees
      </span>
    </div>
  )
}

export default AngleRange

Now for the fun part: rendering the animated background. Let’s apply this to the entire background of the page with an AnimatedBackground wrapper component.

import React, { useContext } from "react"
import { SettingsContext } from "../context/SettingsContext"
const AnimatedBackground = ({ children }) => {
  const { colorSelection, speed, angle } = useContext(SettingsContext)
const background =
  "linear-gradient(" + angle + "deg, " + colorSelection.toString() + ")"
const backgroundSize =
  colorSelection.length * 60 + "%" + " " + colorSelection.length * 60 + "%"
const animation =
  "gradient-animation " +
  colorSelection.length * Math.abs(speed - 11) +
  "s ease infinite"
return (
  <div style={{ background, "background-size": backgroundSize, animation, color: "white" }}>
    {children}
  </div>
  )
}
export default AnimatedBackground

We’re calling the CSS animation for the gradient gradient-animation. We need to add that to styles/globals.css to trigger the animation:

@keyframes gradient-animation {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}

Making it useful to users

Next, let’s add some code output so people can copy and paste the generated CSS and use in their own projects.

import React, { useContext, useState } from "react"
import { SettingsContext } from "../context/SettingsContext"
const Output = () => {
  const [copied, setCopied] = useState(false)
const { colorSelection, speed, angle } = useContext(SettingsContext)
const background =
  "linear-gradient(" + angle + "deg," + colorSelection.toString() + ")"
const backgroundSize =
  colorSelection.length * 60 + "%" + " " + colorSelection.length * 60 + "%"
const animation =
  "gradient-animation " +
  colorSelection.length * Math.abs(speed - 11) +
  "s ease infinite"
const code = `.gradient-background {
  background: ${background};
  background-size: ${backgroundSize};
  animation: ${animation};
}
@keyframes gradient-animation {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}`
return (
    <div
      style={{ position: "relative", maxWidth: "640px", margin: "64px auto" }}
    >
      <pre
        style={{
          background: "#fff",
          color: "#222",
          padding: "32px",
          width: "100%",
          borderRadius: "4px",
          textAlign: "left",
          whiteSpace: "pre",
          boxShadow: "0 2px 8px rgba(0,0,0,.33)",
          overflowX: "scroll",
        }}
      >
        <code>{code}</code>
        <button
          style={{
            position: "absolute",
            top: "8px",
            right: "8px",
            background: "royalblue",
            color: "white",
            padding: "8px 12px",
            borderRadius: "8px",
            border: "none",
            fontSize: "16px",
            cursor: "pointer",
            lineHeight: 1,
          }}
          onClick={() => {
            setCopied(true)
            navigator.clipboard.writeText(code)
          }}
        >
          {copied ? "copied" : "copy"}
        </button>
      </pre>
    </div>
  )
}
export default Output

Making it fun

It is sometimes fun (and useful) to add a button that sets random values on a generator like this. That gives people a way to quickly experiment and see what kinds of results they can get out of the tool. It is also an opportunity to look up cool stuff like how to generate random hex colors.

import React, { useContext } from "react"
import { SettingsContext } from "../context/SettingsContext"

const Random = () => {
  const { setColorSelection, setAngle, setSpeed } = useContext(SettingsContext)

  const goRandom = () => {
    const numColors = 3 + Math.round(Math.random() * 3)
    const colors = [...Array(numColors)].map(() => {
      return "#" + Math.floor(Math.random() * 16777215).toString(16)
    })
    setColorSelection(colors)
    setAngle(Math.floor(Math.random() * 361))
    setSpeed(Math.floor(Math.random() * 10) + 1)
  }

  return (
    <div style={{ padding: "48px 0 16px" }}>
      <button
        onClick={goRandom}
        style={{
          fontSize: "24px",
          fontWeight: 200,
          background: "rgba(255,255,255,.9)",
          color: "blue",
          padding: "24px 48px",
          borderRadius: "8px",
          cursor: "pointer",
          boxShadow: "0 0 4px #000",
          border: "none",
        }}
      >
        RANDOM
      </button>
    </div>
  )
}

export default Random

Wrapping up

There will be a few final things you’ll want to do to wrap up your project for initial release:

  • Update package.json with your project information.
  • Add some links to your personal site, the project’s repository and give credit where its due.
  • Update the README.md file that was generated with default content by Create Next App.

That’s it! We’re ready to release our new cool front end thing generator and reap the rewards of fame and fortune that await us!

You can see the code for this project on GitHub and the demo is hosted on Netlify.


The post Building a Cool Front End Thing Generator appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Categories: Designing, Others Tags:

Stay alert

August 12th, 2021 No comments

A few days ago, Chris wrote up his thoughts about how alert(), confirm(), and prompt() were being deprecated by Chrome and collected a bunch of thoughts from developers. If certain features can essentially be turned off by a major browser, a lot of folks started to worry about the predictability of the web.

On that note, I really liked this note by Richard Harris:

We can’t normalise the attitude that collateral damage is the price of progress, even if we accept the premise — which I don’t — that removing APIs like alert represents progress. For all its flaws, the web is generally agreed to be a stable platform, where investments made today will stand the test of time. A world in which websites are treated as inherently transient objects, where APIs we commonly rely on today could be cast aside as unwanted baggage by tomorrow’s spec wranglers, is a world in which the web has already lost.

This specific bit of drama isn’t of much interest to me, I must admit. But! I think it brings up a super important distinction between software and the web. Here’s a story.

The other day I was faffing about with Astro (which I like a lot). I was rebuilding my personal site with it and I decided — in a spark of punk rock-ness — to update to the latest version of it. I thought perhaps it might make my build process a bit quicker and give me a chance to explore new features. But alas — everything broke. APIs had been deprecated! My build process broke! Everything crumbled down around me.

This isn’t me dunking on Astro. I love it, still. But it’s important to remember that Astro isn’t the web. Neither is React or any other framework, really. Those teams can feel free to deprecate things, improve things as much as they want. They can burn it all to the ground and start again. But stuff like alert(), old CSS features, and HTML elements aren’t in the same category. They can’t be deprecated in the same way because, as Jeremy said, the web needs to be predictable. And we can’t treat the web like plain ol’ software because no one team or individual owns those features.

Here’s the gist of my rant: alert() and confirm() aren’t features of Chrome, but of the web. But I fear that’s how a lot of folks might think about them.

This is also why standards are so important! Talking about new features in public lets us fix all the bugs and answer all the questions before a new feature ships onto this platform where you can’t just delete it when you realize you goofed up. I’m not even really dunking on Chrome here either, but this distinction between software and the open web is an important one to make. Right?

Direct Link to ArticlePermalink


The post Stay alert appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Categories: Designing, Others Tags:

Using Web Components in WordPress is Easier Than You Think

August 12th, 2021 No comments

Now that we’ve seen that web components and interactive web components are both easier than you think, let’s take a look at adding them to a content management system, namely WordPress.

There are three major ways we can add them. First, through manual input into the siteputting them directly into widgets or text blocks, basically anywhere we can place other HTML. Second, we can add them as the output of a theme in a theme file. And, finally, we can add them as the output of a custom block.

Loading the web component files

Now whichever way we end up adding web components, there’s a few things we have to ensure:

  1. our custom element’s template is available when we need it,
  2. any JavaScript we need is properly enqueued, and
  3. any un-encapsulated styles we need are enqueued.

We’ll be adding the web component from my previous article on interactive web components. Check out the code over at CodePen.

Let’s hit that first point. Once we have the template it’s easy enough to add that to the WordPress theme’s footer.php file, but rather than adding it directly in the theme, it’d be better to hook into wp_footer so that the component is loaded independent of the footer.php file and independent of the overall theme— assuming that the theme uses wp_footer, which most do. If the template doesn’t appear in your theme when you try it, double check that wp_footer is called in your theme’s footer.php template file.

<?php function diy_ezwebcomp_footer() { ?>
  <!-- print/echo Zombie profile template code. -->
  <!-- It's available at https://codepen.io/undeadinstitute/pen/KKNLGRg -->
<?php } 
add_action( 'wp_footer', 'diy_ezwebcomp_footer');

Next is to enqueue our component’s JavaScript. We can add the JavaScript via wp_footer as well, but enqueueing is the recommended way to link JavaScript to WordPress. So let’s put our JavaScript in a file called ezwebcomp.js (that name is totally arbitrary), stick that file in the theme’s JavaScript directory (if there is one), and enqueue it (in the functions.php file).

wp_enqueue_script( 'ezwebcomp_js', get_template_directory_uri() . '/js/ezwebcomp.js', '', '1.0', true );

We’ll want to make sure that last parameter is set to true , i.e. it loads the JavaScript before the closing body tag. If we load it in the head instead, it won’t find our HTML template and will get super cranky (throw a bunch of errors.)

If you can fully encapsulate your web component, then you can skip this next step. But if you (like me) are unable to do it, you’ll need to enqueue those un-encapsulated styles so that they’re available wherever the web component is used. (Similar to JavaScript, we could add this directly to the footer, but enqueuing the styles is the recommended way to do it). So we’ll enqueue our CSS file:

wp_enqueue_style( 'ezwebcomp_style', get_template_directory_uri() . '/ezwebcomp.css', '', '1.0', 'screen' );

That wasn’t too tough, right? And if you don’t plan to have any users other than Administrators use it, you should be all set for adding these wherever you want them. But that’s not always the case, so we’ll keep moving ahead!

Don’t filter out your web component

WordPress has a few different ways to both help users create valid HTML and prevent your Uncle Eddie from pasting that “hilarious” picture he got from Shady Al directly into the editor (complete with scripts to pwn every one of your visitors).

So when adding web-components directly into blocks or widgets, we’ll need to be careful about WordPress’s built-in code filtering . Disabling it all together would let Uncle Eddie (and, by extension, Shady Al) run wild, but we can modify it to let our awesome web component through the gate that (thankfully) keeps Uncle Eddie out.

First, we can use the wp_kses_allowed filter to add our web component to the list of elements not to filter out. It’s sort of like we’re whitelisting the component, and we do that by adding it to the the allowed tags array that’s passed to the filter function.

function add_diy_ezwebcomp_to_kses_allowed( $the_allowed_tags ) {
  $the_allowed_tags['zombie-profile'] = array();
}
add_filter( 'wp_kses_allowed_html', 'add_diy_ezwebcomp_to_kses_allowed');

We’re adding an empty array to the component because WordPress filters out attributes in addition to elements—which brings us to another problem: the slot attribute (as well as part and any other web-component-ish attribute you might use) are not allowed by default. So, we have to explitcly allow them on every element on which you anticipate using them, and, by extension, any element your user might decide to add them to. (Wait, those element lists aren’t the same even though you went over it six times with each user… who knew?) Thus, below I have set slot to true on , and

    , the three elements I’m putting into slots in the component. (I also set part to true on span elements so that I could let that attribute through too.)

    function add_diy_ezwebcomp_to_kses_allowed( $the_allowed_tags ) {
      $the_allowed_tags['zombie-profile'] = array();
      $the_allowed_tags['span']['slot'] = true;
      $the_allowed_tags['span']['part'] = true;
      $the_allowed_tags['ul']['slot'] = true;
      $the_allowed_tags['img']['slot'] = true;
      return $the_allowed_tags;
    }
    add_filter( 'wp_kses_allowed_html', 'add_diy_ezwebcomp_to_kses_allowed');
    

    We could also enable the slot (and part) attribute in all allowed elements with something like this:

    function add_diy_ezwebcomp_to_kses_allowed($the_allowed_tags) {
      $the_allowed_tags['zombie-profile'] = array();
      foreach ($the_allowed_tags as &$tag) {
        $tag['slot'] = true;
        $tag['part'] = true;
      }
      return $the_allowed_tags;
    }
    add_filter('wp_kses_allowed_html', 'add_diy_ezwebcomp_to_kses_allowed');
    

    Sadly, there is one more possible wrinkle with this. You may not run into this if all the elements you’re putting in your slots are inline/phrase elements, but if you have a block level element to put into your web component, you’ll probably get into a fistfight with the block parser in the Code Editor. You may be a better fist fighter than I am, but I always lost.

    The code editor is an option that allows you to inspect and edit the markup for a block.

    For reasons I can’t fully explain, the client-side parser assumes that the web component should only have inline elements within it, and if you put a

      or

      ,

      or some other block-level element in there, it’ll move the closing web component tag to just after the last inline/phrase element. Worse yet, according to a note in the WordPress Developer Handbook, it’s currently “not possible to replace the client-side parser.”

      While this is frustrating and something you’ll have to train your web editors on, there is a workaround. If we put the web component in a Custom HTML block directly in the Block Editor, the client-side parser won’t leave us weeping on the sidewalk, rocking back and forth, and questioning our ability to code… Not that that’s ever happened to anyone… particularly not people who write articles…

      Component up the theme

      Outputting our fancy web component in our theme file is straightforward as long as it isn’t updated outside the HTML block. We add it the way we would add it in any other context, and, assuming we have the template, scripts and styles in place, things will just work.

      But let’s say we want to output the contents of a WordPress post or custom post type in a web component. You know, write a post and that post is the content for the component. This allows us to use the WordPress editor to pump out an archive of elements. This is great because the WordPress editor already has most of the UI we need to enter the content for one of the components:

      • The post title can be the zombie’s name.
      • A regular paragraph block in the post content can be used for the zombie’s statement.
      • The featured image can be used for the zombie’s profile picture.

      That’s most of it! But we’ll still need fields for the zombie’s age, infection date, and interests. We’ll create these with WordPress’s built in Custom Fields feature.

      We’ll use the template part that handles printing each post, e.g. content.php, to output the web component. First, we’ll print out the opening tag followed by the post thumbnail (if it exists).

      <zombie-profile>
        <?php 
          // If the post featured image exists...
          if (has_post_thumbnail()) {
            $src = wp_get_attachment_image_url(get_post_thumbnail_id()); ?>
            <img src="<?php echo $src; ?>" slot="profile-image">
          <?php
          }
        ?>

      Next we’ll print the title for the name

      <?php
        // If the post title field exits...
        if (get_the_title()) { ?>
        <span slot="zombie-name"><?php echo get_the_title(); ?></span>
        <?php
        }
      ?>

      In my code, I have tested whether these fields exist before printing them for two reasons:

      1. It’s just good programming practice (in most cases) to hide the labels and elements around empty fields.
      2. If we end up outputting an empty for the name (e.g. ), then the field will show as empty in the final profile rather than use our web component’s built-in default text, image, etc. (If you want, for instance, the text fields to be empty if they have no content, you can either put in a space in the custom field or skip the if statement in the code).

      Next, we will grab the custom fields and place them into the slots they belong to. Again, this goes into the theme template that outputs the post content.

      <?php
        // Zombie age
        $temp = get_post_meta(the_ID(), 'Age', true);
        if ($temp) { ?>
          <span slot="z-age"><?php echo $temp; ?></span>
          <?php
        }
        // Zombie infection date
        $temp = get_post_meta(the_ID(), 'Infection Date', true);
        if ($temp) { ?>
          <span slot="idate"><?php echo $temp; ?></span>
          <?php
        }
        // Zombie interests
        $temp = get_post_meta(the_ID(), 'Interests', true);
        if ($temp) { ?>
          <ul slot="z-interests"><?php echo $temp; ?></ul>
          <?php
        }
      ?>

      One of the downsides of using the WordPress custom fields is that you can’t do any special formatting, A non-technical web editor who’s filling this out would need to write out the HTML for the list items (

    • ) for each and every interest in the list. (You can probably get around this interface limitation by using a more robust custom field plugin, like Advanced Custom Fields, Pods, or similar.)

      Lastly. we add the zombie’s statement and the closing tag.

      <?php
        $temp = get_the_content();
        if ($temp) { ?>
          <span slot="statement"><?php echo $temp; ?></span>
        <?php
        }
      ?>
      </zombie-profile>

      Because we’re using the body of the post for our statement, we’ll get a little extra code in the bargain, like paragraph tags around the content. Putting the profile statement in a custom field will mitigate this, but depending on your purposes, it may also be intended/desired behavior.

      You can then add as many posts/zombie profiles as you need simply by publishing each one as a post!

      Block party: web components in a custom block

      Creating a custom block is a great way to add a web component. Your users will be able to fill out the required fields and get that web component magic without needing any code or technical knowledge. Plus, blocks are completely independent of themes, so really, we could use this block on one site and then install it on other WordPress sites—sort of like how we’d expect a web component to work!

      There are the two main parts of a custom block: PHP and JavaScript. We’ll also add a little CSS to improve the editing experience.

      First, the PHP:

      function ez_webcomp_register_block() {
        // Enqueues the JavaScript needed to build the custom block
        wp_register_script(
          'ez-webcomp',
          plugins_url('block.js', __FILE__),
          array('wp-blocks', 'wp-element', 'wp-editor'),
          filemtime(plugin_dir_path(__FILE__) . 'block.js')
        );
      
        // Enqueues the component's CSS file
        wp_register_style(
          'ez-webcomp',
          plugins_url('ezwebcomp-style.css', __FILE__),
          array(),
          filemtime(plugin_dir_path(__FILE__) . 'ezwebcomp-style.css')
        );
      
        // Registers the custom block within the ez-webcomp namespace
        register_block_type('ez-webcomp/zombie-profile', array(
          // We already have the external styles; these are only for when we are in the WordPress editor
          'editor_style' =&gt; 'ez-webcomp',
          'editor_script' =&gt; 'ez-webcomp',
        ));
      }
      add_action('init', 'ez_webcomp_register_block');
      

      The CSS isn’t necessary, it does help prevent the zombie’s profile image from overlapping the content in the WordPress editor.

      /* Sets the width and height of the image.
       * Your mileage will likely vary, so adjust as needed.
       * "pic" is a class we'll add to the editor in block.js
      */
      #editor .pic img {
        width: 300px;
        height: 300px;
      }
      /* This CSS ensures that the correct space is allocated for the image,
       * while also preventing the button from resizing before an image is selected.
      */
      #editor .pic button.components-button { 
        overflow: visible;
        height: auto;
      }
      

      The JavaScript we need is a bit more involved. I’ve endeavored to simplify it as much as possible and make it as accessible as possible to everyone, so I’ve written it in ES5 to remove the need to compile anything.

      Show code
      (function (blocks, editor, element, components) {
        // The function that creates elements
        var el = element.createElement;
        // Handles text input for block fields 
        var RichText = editor.RichText;
        // Handles uploading images/media
        var MediaUpload = editor.MediaUpload;
          
        // Harkens back to register_block_type in the PHP
        blocks.registerBlockType('ez-webcomp/zombie-profile', {
          title: 'Zombie Profile', //User friendly name shown in the block selector
          icon: 'id-alt', //the icon to usein the block selector
          category: 'layout',
          // The attributes are all the different fields we'll use.
          // We're defining what they are and how the block editor grabs data from them.
          attributes: {
            name: {
              // The content type
              type: 'string',
              // Where the info is available to grab
              source: 'text',
              // Selectors are how the block editor selects and grabs the content.
              // These should be unique within an instance of a block.
              // If you only have one img or one <ul> etc, you can use element selectors.
              selector: '.zname',
            },
            mediaID: {
              type: 'number',
            },
            mediaURL: {
              type: 'string',
              source: 'attribute',
              selector: 'img',
              attribute: 'src',
            },
            age: {
              type: 'string',
              source: 'text',
              selector: '.age',
            },
            infectdate: {
              type: 'date',
              source: 'text',
              selector: '.infection-date'
            },
            interests: {
              type: 'array',
              source: 'children',
              selector: 'ul',
            },
            statement: {
              type: 'array',
              source: 'children',
              selector: '.statement',
            },
        },
        // The edit function handles how things are displayed in the block editor.
        edit: function (props) {
          var attributes = props.attributes;
          var onSelectImage = function (media) {
            return props.setAttributes({
              mediaURL: media.url,
              mediaID: media.id,
            });
          };
          // The return statement is what will be shown in the editor.
          // el() creates an element and sets the different attributes of it.
          return el(
            // Using a div here instead of the zombie-profile web component for simplicity.
            'div', {
              className: props.className
            },
            // The zombie's name
            el(RichText, {
              tagName: 'h2',
              inline: true,
              className: 'zname',
              placeholder: 'Zombie Name…',
              value: attributes.name,
              onChange: function (value) {
                props.setAttributes({
                  name: value
                });
              },
            }),
            el(
              // Zombie profile picture
              'div', {
                className: 'pic'
              },
              el(MediaUpload, {
                onSelect: onSelectImage,
                allowedTypes: 'image',
                value: attributes.mediaID,
                render: function (obj) {
                  return el(
                    components.Button, {
                      className: attributes.mediaID ?
                        'image-button' : 'button button-large',
                      onClick: obj.open,
                    },
                    !attributes.mediaID ?
                    'Upload Image' :
                    el('img', {
                      src: attributes.mediaURL
                    })
                  );
                },
              })
            ),
            // We'll include a heading for the zombie's age in the block editor
            el('h3', {}, 'Age'),
            // The age field
            el(RichText, {
              tagName: 'div',
              className: 'age',
              placeholder: 'Zombie's Age…',
              value: attributes.age,
              onChange: function (value) {
                props.setAttributes({
                  age: value
                });
              },
            }),
            // Infection date heading
            el('h3', {}, 'Infection Date'),
            // Infection date field
            el(RichText, {
              tagName: 'div',
              className: 'infection-date',
              placeholder: 'Zombie's Infection Date…',
              value: attributes.infectdate,
              onChange: function (value) {
                props.setAttributes({
                  infectdate: value
                });
              },
            }),
            // Interests heading
            el('h3', {}, 'Interests'),
            // Interests field
            el(RichText, {
              tagName: 'ul',
              // Creates a new <li> every time `Enter` is pressed
              multiline: 'li',
              placeholder: 'Write a list of interests…',
              value: attributes.interests,
              onChange: function (value) {
                props.setAttributes({
                  interests: value
                });
              },
              className: 'interests',
            }),
            // Zombie statement heading
            el('h3', {}, 'Statement'),
            // Zombie statement field
            el(RichText, {
              tagName: 'div',
              className: "statement",
              placeholder: 'Write statement…',
              value: attributes.statement,
              onChange: function (value) {
                props.setAttributes({
                  statement: value
                });
              },
            })
          );
        },
      
        // Stores content in the database and what is shown on the front end.
        // This is where we have to make sure the web component is used.
        save: function (props) {
          var attributes = props.attributes;
          return el(
            // The <zombie-profile web component
            'zombie-profile',
            // This is empty because the web component does not need any HTML attributes
            {},
            // Ensure a URL exists before it prints
            attributes.mediaURL &&
            // Print the image
            el('img', {
              src: attributes.mediaURL,
              slot: 'profile-image'
            }),
            attributes.name &&
            // Print the name
            el(RichText.Content, {
              tagName: 'span',
              slot: 'zombie-name',
              className: 'zname',
              value: attributes.name,
            }),
            attributes.age &&
            // Print the zombie's age
            el(RichText.Content, {
              tagName: 'span',
              slot: 'z-age',
              className: 'age',
              value: attributes.age,
          }),
            attributes.infectdate &&
            // Print the infection date
            el(RichText.Content, {
              tagName: 'span',
              slot: 'idate',
              className: 'infection-date',
              value: attributes.infectdate,
          }),
            // Need to verify something is in the first element since the interests's type is array
            attributes.interests[0] &&
            // Pint the interests
            el(RichText.Content, {
              tagName: 'ul',
              slot: 'z-interests',
              value: attributes.interests,
            }),
            attributes.statement[0] &&
            // Print the statement
            el(RichText.Content, {
              tagName: 'span',
              slot: 'statement',
              className: 'statement',
              value: attributes.statement,
          })
          );
          },
        });
      })(
        //import the dependencies
        window.wp.blocks,
        window.wp.blockEditor,
        window.wp.element,
        window.wp.components
      );

      Plugging in to web components

      Now, wouldn’t it be great if some kind-hearted, article-writing, and totally-awesome person created a template that you could just plug your web component into and use on your site? Well that guy wasn’t available (he was off helping charity or something) so I did it. It’s up on github:

      Do It Yourself – Easy Web Components for WordPress

      The plugin is a coding template that registers your custom web component, enqueues the scripts and styles the component needs, provides examples of the custom block fields you might need, and even makes sure things are styled nicely in the editor. Put this in a new folder in /wp-content/plugins like you would manually install any other WordPress plugin, make sure to update it with your particular web component, then activate it in WordPress on the “Installed Plugins” screen.

      Not that bad, right?

      Even though it looks like a lot of code, we’re really doing a few pretty standard WordPress things to register and render a custom web component. And, since we packaged it up as a plugin, we can drop this into any WordPress site and start publishing zombie profiles to our heart’s content.

      I’d say that the balancing act is trying to make the component work as nicely in the WordPress block editor as it does on the front end. We would have been able to knock this out with a lot less code without that consideration.

      Still, we managed to get the exact same component we made in my previous articles into a CMS, which allows us to plop as many zombie profiles on the site. We combined our knowledge of web components with WordPress blocks to develop a reusable block for our reusable web component.

      What sort of components will you build for your WordPress site? I imagine there are lots of possibilities here and I’m interested to see what you wind up making.

      Article series

      1. Web Components Are Easier Than You Think
      2. Interactive Web Components Are Easier Than You Think
      3. Using Web Components in WordPress is Easier Than You Think

      The post Using Web Components in WordPress is Easier Than You Think appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

    • Categories: Designing, Others Tags:

Wanna see a whiter white?

August 11th, 2021 No comments

Heck of a CSS trick here from Dongsung Kim.

There are hidden HDR videos playing at the corners of this page. When a HDR-capable browser encounters one, it switches to HDR mode. For some reason, CSS backdrop-filter + brightness >100% combo seems to behave like HDR—reaching beyond the user-controlled display brightness, up to the maximum HDR brightness—while the everything in between follow[s] along. At least that’s the overall idea, but I still don’t know exactly why it works; especially why with those two CSS properties.

As I look at that demo in Chrome, I see an extra-white text-shadow. In Safari, I see extra-white text. In Firefox, the whites match so I see nothing. Probably a bug.

I wouldn’t recommend actually using the trick, as I’d think the extra-whiteness almost certainly takes extra battery power that a user isn’t opting into, even without the video playing—even though it does feel like a bummer that our screens are capable of whiter whites than we normally have access to. The good news is that the gamut of color on the web is expanding, generally.

Direct Link to ArticlePermalink


The post Wanna see a whiter white? appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Categories: Designing, Others Tags:

Build Your Site The Easy Way With TagDiv Newspaper

August 11th, 2021 No comments

Ready to take your business online but not sure where to start? It’s a surprisingly simple process, made all the easier by the tagDiv Newspaper theme that can shoulder the burden of code, leaving you to be creative.

Professional web designers normally begin with broad brushstrokes, roughly hewing a site, before finessing on the finer details; that’s exactly what tagDiv’s Newspaper theme lets you do, with innovative tools and a huge selection of pre-built options to choose from.

What is the Newspaper Theme?

Newspaper is the best-selling magazine theme from tagDiv. In constant development over the last twelve years, it’s been used to create world-beating sites for clients as diverse and demanding as United Nations, ShareAmerica, The Rackspace Blog, Bitcoin News, Uber Engineering, and Tech Explorist.

As the name implies, the Newspaper theme is primarily a magazine or blog theme, but you can use it for any kind of site, in any type of industry.

Packed with intuitive features that make personal web development not just possible but enjoyable, it will have your site ready to launch in no time.

It is fully compatible with Gutenberg, WordPress’ drag-n-drop site builder; it also comes with its own WYSIWYG, tagDiv Composer. All the sites built in Newspaper are fully flexible, responsive, mobile-friendly, and retina-ready. Newspaper is even fully integrated with WooCommerce so that you can transform your magazine site into a fully-featured ecommerce store.

Newspaper has been carefully coded to make the most of the upcoming Core Web Vitals update from Google, so your new site will be well-placed to rank highly on search engines.

Now that you know a little about the background of the Newspaper theme let’s look at how we can use it to build a WordPress site.

Pre-Built Websites

Sometimes it’s not just your coding skills but your design skills that are lacking; you know what kind of site that you want, you’re just hazy on the details.

This is where tagDiv’s Newspaper theme comes into its own. With a single click, you can install an entire pre-built website. And the process is so fast and convenient that you can try out as many as you like and pick the one that matches your vision.

You can even import a whole ton of pre-written content for testing the sites out, so you can see how it will look with your content without spending hours typing or copying and pasting text out of a Word doc.

There are 120 different designs covering all kinds of different industries. This means no matter what kind of site you’re building, one click, and you’re ready to go live.

Cloud Library

One step up from a full pre-built website is tagDiv’s Cloud Library. If you’ve installed one of the pre-built websites, this is probably where you want to go next.

The Cloud Library is a collection of 1600 different design elements that can be mixed and matched with live-editing to fast-track your site creation. You’ll find content blocks like headers, footers, testimonials, banners, and featured items. You can mix-n-match them however you please to create the site of your dreams.

Putting the “Cloud” into the Cloud Library are tagDiv’s servers, storing the code for each of these elements, so your installation only needs to load the code you actually use. This provides a huge boost in performance.

Composer

Lastly, the Newspaper theme provides tagDiv Composer, a specialist WordPress builder — like Gutenberg — that allows you to customize your website with absolutely no coding skills whatsoever. It’s a powerful yet simple-to-use tool that allows you to edit the elements of the Cloud Library and adapt them to your own purposes.

With Composer, you can create your own headers, footers, banners, text blocks, and more without any of the limitations of cookie-cutter design.

tagDiv Composer gives you the ultimate control over your site. You’ll find all the essential elements you need, from text and buttons to images and videos. All you have to do is drag and drop them into place.

Building a Site With tagDiv Newspaper Theme

As you can see that the fastest way to an engaging and original website is, to begin with, a pre-built site, then add the different blocks of code you want from the Cloud Library, and finally customize them with the Composer.

To make this possible, tagDiv has brought together experts from multiple disciplines, including brand strategy, project management, and web development.

It’s a slick system for quickly publishing high-quality sites that are unique to you and your business. Trusted by more than 130,000 customers worldwide, the Newspaper has earned tagDiv the status of Power Elite Author on ThemeForest and Top Author on Envato.

The Newspaper theme costs just $59, which includes six months of support from tagDiv, but for just $17.63, you can extend support to 12 months for added peace of mind.

tagDiv Newspaper is the simplest way for you to take your business online using WordPress.

 

[— This is a sponsored post on behalf of tagDiv —]

Source

The post Build Your Site The Easy Way With TagDiv Newspaper first appeared on Webdesigner Depot.

Categories: Designing, Others Tags:

Static vs. Dynamic vs. Jamstack: Where’s The Line?

August 11th, 2021 No comments
Two brown backed leather chairs with a black frame and legs around a white table with a decorative green succulent plant in a white vase.

You’ll often hear developers talking about “static” vs. “dynamic” sites, or you may have heard someone use the term Jamstack. What do these terms mean, and when does a “static” site become either a Jamstack or dynamic site? These questions sound simple, but they’re more nuanced than they appear. Let’s explore these terms to gain a deeper understanding of Jamstack.

Finding the line

What’s the difference between a chair and a stool? Most people will respond that a chair has four legs and back support, whereas a stool has three legs with no back support.

Credit: Rumman Amin
Two tall brown barstools with three legs and a brass frame under a natural wood countertop with a decorative green houseplant.
Credit: Rumman Amin

OK, that’s a great starting point, but what about these?

The more stool-like a chair becomes, the fewer people will unequivocally agree that it’s a chair. Eventually, we’ll reach a point where most people agree it’s a stool rather than a chair. It may sound like a silly exercise, but if we want to have a deep appreciation of what it means to be a chair, it’s a valuable one. We find out where the limits of a chair are for most people. We also build an understanding of the gray area beyond. Eventually, we get to the point where even the biggest die-hard chair fans concede and admit there’s a stool in front of them.

As interesting as chairs are, this is an article about website delivery technology. Let’s perform this same exercise for static, dynamic, and Jamstack websites.

At a high level

When you go to a website in your browser, there’s a lot going on behind the scenes:

  1. Your browser performs a DNS lookup to turn the domain name into an IP address.
  2. It requests an HTML file from that IP address.
  3. The webserver sends back the requested file.
  4. As the browser renders the web page, it may come across a reference for an asset, such as a CSS, JavaScript, or image file. The browser then performs a request for this asset.
  5. This cycle continues until the browser has all the files for the web page. It’s not unusual for a single webpage to make 50+ requests.

For every request, the response from the webserver is always a static file, even on a dynamic website. You could save these files to a USB drive, email them to a friend just like any other file on your computer.

When comparing static and dynamic, we’re talking about what the webserver is doing. On a static site, the files the browser requests already exist on the webserver. The webserver sends them back exactly as they are. On a dynamic site, the response gets generated by software. This software might connect to a database to retrieve data, build a layout from template files, and add today’s date to the footer. It does all of this for every request.

That’s the foundational difference between static and dynamic websites.

Where does Jamstack fit in?

Static websites are restrictive. They’re great for informational websites; however, you can’t have any dynamic content or behavior by definition. Jamstack blurs the line between static and dynamic. The idea is to take advantage of all the things that make static websites awesome while enabling dynamic functionality where necessary.

The ‘stack’ in Jamstack is a misnomer. The truth is, Jamstack is not a stack at all. It’s a philosophy that exhibits a striking resemblance to The 5 Pillars of the AWS Well-Architected Framework. The ambiguity in the term has led to extensive community discussion about what it means to be Jamstack.

What is Jamstack?

Jamstack is a superset of static. But to truly understand Jamstack, let’s start with the seeds that led to the coining of the term.

In 2002, the late Aaron Swartz published a blog post titled “Bake, Don’t Fry.” While Aaron didn’t coin “Bake, Don’t Fry,” it’s the first time I can find someone recognizing the benefits of static websites while breaking out perceived constraints of the word.

I care about not having to maintain cranky AOLserver, Postgres and Oracle installs. I care about being able to back things up with scp. I care about not having to do any installation or configuration to move my site to a new server. I care about being platform and server independent.

If we trawl through history, we can find similar frustrations that led to Jamstack seeds:

  • Ben and Mena Trott created MovableType because of a [d]issatisfaction with existing blog CMSes — performance, stability.
  • Tom Preston-Werner created Jekyll to move away from complexity:

    I already knew a lot about what I didn’t want. I was tired of complicated blogging engines like WordPress and Mephisto. I wanted to write great posts, not style a zillion template pages, moderate comments all day long, and constantly lag behind the latest software release.

  • Steve Francia created Hugo for performance:

    The past few years this blog has [been] powered by wordpress [sic] and drupal prior to that. Both are are fine pieces of software, but over time I became increasingly disappointed with how they are both optimized for writing content even though significantly most common usage is reading content. Due to the need to load the PHP interpreter on each request it could never be considered fast and consumed a lot of memory on my VPS.

The same themes surface as you look at the origins of many early Jamstack tools:

  • Reduce complexity
  • Improve performance
  • Reduce vendor lock-in
  • Better workflows for developers

In the past 20 years, JavaScript has evolved from a language for adding small interactions to a website to becoming a platform for building rich web applications in the browser. In parallel, we’ve seen a movement of splitting large applications into smaller microservices. These two developments gave rise to a new way of building websites where you could have a static front-end decoupled from a dynamic back-end.

In 2015, Mathias Biilmann wanted to talk about this modern way of building websites but was struggling with the constricting definition of static:

We were in this space of modern static websites. That’s a really bad description of what we’re doing, right? And we kept having that problem that, talking to people about static sites, they would think about something very static. They would think about a brochure or something with no moving parts. A little one-pager or something like that.

To break out of these constraints, he coined the term “Jamstack” to talk about this new approach, and it caught on like wildfire. What was old static technology from the 90s became new again and pushed to new limits. Many developers caught on to the benefits of the Jamstack approach, which helped Jamstack grow into the thriving ecosystem it is today.

Aaron Swartz put it nicely, 13 years before Jamstack was coined: keep a strict separation between input (which needs dynamic code to be processed) and output (which can usually be baked). In other words, decouple the front end from the back end. Prerender content whenever possible. Layer on dynamic functionality where necessary. That’s the crux of Jamstack.

The reason you might want to build a Jamstack site over a dynamic site come down to the six pillars of Jamstack:

Security

Jamstack sites have fewer moving parts and less surface area for malicious exploitation from outside sources.

Scale

Jamstack sites are static where possible. Static sites can live entirely in a CDN, making them much easier and cheaper to scale.

Performance

Serving a web page from a CDN rather than generating it from a centralized server on-demand improves the page load speed.

Maintainability

Static websites are simple. You need a webserver capable of serving files. With a dynamic site, you might need an entire team to keep a website online and fast.

Portability

Again, a static website is made up of files. As long as you find a webserver capable of serving website files, you can move your site anywhere.

Developer experience

Git workflows are a core part of software development today. With many legacy CMSs, it’s difficult to have Git development workflows. With a Jamstack site, everything is a file making it seamless to use Git.

Chris touches on some of these points in a deep-dive comparison between Jamstack and WordPress. He also compares the reasons for choosing a Jamstack architecture versus a server-side one in “Static or Not?”.

Let’s use these pillars to evaluate Jamstack use cases.

Where is the edge of static and Jamstack?

Now that we have the basics of static and Jamstack, let’s dive in and see what lies at the edge of each definition. We have four categories each edge case can fall under.

  • Static – This strictly adheres to the definition of static.
  • Basically static – While not precisely static, most people would call it a static site.
  • Jamstack – A static frontend decoupled from a dynamic backend.
  • Dynamic – Renders web pages on-demand.

Many of these use cases can be placed in multiple categories. In this exercise, we’re putting them in the most restrictive category they fit.

JavaScript interaction Static

Let’s start with an easy one. I have a static site that uses JavaScript to create a slideshow of images.

The HTML page, JavaScript, and images are all static files. All of the HTML manipulation required for the slideshow to function happens in the browser with no external influence.

Cookies Static

I have a static site that adds a banner to the top of the page using JavaScript if a cookie exists. A cookie is just a header. The rest of the files are static.

External assets Basically Static

On a web page, we can load images or JavaScript from an external source. This external source may generate these assets dynamically on request. Would that mean we have a dynamic site?

Most people, including myself, would consider this a static site because it basically is. But if we’re strict to the definition, it doesn’t fit the bill. Having any part of the page generated dynamically defiles the sacred harmony of static.

iFrames Basically Static

An inline frame allows you to embed an HTML page within another HTML page. iFrames are commonly used for embedding Google Maps, Facebook Like buttons, and YouTube videos on a webpage.

Again, most people would still consider this a static site. However, these embeds are almost always from a dynamically-generated source.

Forms Basically Static

A static site can undoubtedly have a form on it. The dilemma comes when you submit it. If you want to do something with the data, you almost certainly need a dynamic back-end. There are plenty of form submission services you can use as the action for your form.

I can see two ways to argue this:

  1. You’re submitting a form to an external website, and it happens to redirect back afterward. This separation means the definition of static remains intact.
  2. This external service is a core workflow on your website, the definition of static no longer works.

In reality, most people would still consider this a static site.

Ajax requests Jamstack

An Ajax request allows a developer to request data from an external source without reloading the page. We’re in the same boat as the above situations of relying on a third party. It’s possible the endpoint for the Ajax call is a static JSON file, but it’s more likely that it’s dynamically-generated.

The nature of how Ajax data is typically used on a website pushes it past a static website into Jamstack territory. It fits well with Jamstack as you can have a site where you prerender everything you can, then use Ajax to layer on any dynamic functionality or content on the site.

Embedded eCommerce Jamstack

There are services that allow you to add eCommerce, even to static websites. Behind the scenes, they’re essentially making Ajax requests to manage items in a shopping cart and collect payment details.

Single page application (SPA) Jamstack

The title alone puts it out of static site contention. A SPA uses Ajax calls to request data. The presentation layer lives entirely in the front end, making it Jamtastic.

Ajax call to a serverless function Jamstack

Whether the endpoint of an Ajax call is serverless with something like AWS Lambda, goes to your Kubernetes clustered Node.js back-end, or a simple PHP back-end, it doesn’t matter. The key for Jamstack is the front end is independent of the back end.

Reverse proxy in front of a webserver Static

Adding a reverse proxy in front of the webserver for a static site must make it dynamic, right? Well, not so fast. While a proxy is software that adds a dynamic element to the network, as long as the file on the server is precisely the file the browser receives, it’s still static.

A webserver, modem, and every piece of network infrastructure in between are running software. If adding a proxy makes a static site dynamic, then nothing is static.

CDN Static

A CDN is a globally-distributed reverse proxy, so it falls into the same category as a reverse proxy. CDNs often add their own headers. This still doesn’t impact the prestigious static status as the headers aren’t part of the file sitting on the server’s hard drive.

CDN in front of a dynamic site with a 200-year cache expiration time Dynamic

OK, 200 years is a long expiry time, I’ll give you that. There are two reasons this is neither a static nor Jamstack site:

  1. The first request isn’t cached, so it generates on demand.
  2. CDNs aren’t designed for persistent storage. If, after one week, you’ve only had five hits on your website, the CDN might purge your web page from the cache. It can always retrieve the web page from the origin server, which would dynamically render the response.

WordPress with a static output Static

Using a WordPress plugin like WP2Static lets you create and manage your website in WordPress and output a static website whenever something changes.

When you do this, the files the browser requests already exist on the webserver, making it a static website—a subtle but important distinction from having a CDN in front of a dynamic site.

Edge computing Dynamic

Many companies are now offering the ability to run dynamic code at the edge of a CDN. It’s a powerful concept because you can have dynamic functionality without adding latency to the user. You can even use edge computation to manipulate HTML before sending it to the client.

It comes down to how you’re using edge functions. You could use an edge function to add a header to particular requests. I would argue this is still a static site. Push much beyond this, where you’re manipulating the HTML, and you’ve crossed the dynamic boundary.

It’s hard to argue it’s a Jamstack site as it doesn’t adhere to some of the fundamental benefits: scale, maintainability, and portability. Now, you have a piece of your core infrastructure that’s changing HTML on every request, and it will only work on that particular hosting infrastructure. That’s getting pretty far away from the blissful simplicity of a static site.

One of the elegant things about Jamstack is the front end and back end are decoupled. The backend is made up of APIs that output data. They don’t know or care how the data is used. The front end is the presentation layer. It knows where to get dynamic data from and how to render it. When you break this separation of concerns, you’ve crossed into a dynamic world.

Dynamic Persistent Rendering (DPR) Dynamic

DPR is a strategy to reduce long build times on large static site generator (SSG) sites. The idea is the SSG builds a subset of the most popular pages. For the rest of the pages, the SSG builds them on-demand the first time they’re requested and saves them to persistent storage. After the initial request, the page behaves precisely like the rest of the built static pages.

Long build times limit large-scale use cases from choosing Jamstack. If all the SSG tooling were GoLang-based, we probably wouldn’t need DPR. However, that’s not the direction most Jamstack tooling has taken, and build performance can be excruciatingly long on big websites.

DPR is a means to an end and a necessity for Jamstack to grow. While it allows you to use Jamstack workflows on massive websites, ironically, I don’t think you can call a site using DPR a Jamstack site. Running software on-demand to generate a web page certainly sounds dynamicy. After the first request, a page served using DPR is a static page which makes DPR “more static” than putting a CDN in front of a dynamic site. However, it’s still a dynamic site as there isn’t a separation between frontend and backend, and it’s not portable, one of the pillars of a Jamstack site.

Incremental Static Regeneration (ISR) Dynamic

ISR is a similar but subtly different strategy to DPR to reduce long build times on large SSG sites. The difference is you can revalidate individual pages periodically to mimic a dynamic site without doing an entire site build.

Requests to a page without a cached version fall back to a stale version of that page or a generic loading page.

Again, it’s an exciting technology that expands what you can do with Jamstack workflows, but dynamically generating a page on-demand sounds like something a dynamic site would do.

Flat file CMS Dynamic

A flat file CMS uses text files for content rather than a database. While flat file CMSs remove a dynamic element from the stack, it’s still dynamically rendering the response.

The lines have been drawn

Exploring and debating these edge cases gives us a better understanding of the limits of all of these terms. The point of this exercise isn’t to be dogmatic about creating static or Jamstack websites. It’s to give us a common language to talk about the tradeoffs you make as you cross the boundary from one concept to another.

There’s absolutely nothing wrong with tradeoffs either. Not everything can be a purely static website. In many cases, the trade-offs make sense. For example, let’s say the front end needs to know the country of the visitor. There are two ways to do this:

  1. On page load, perform an Ajax call to query the country from an API. (Jamstack)
  2. Use an edge function to dynamically insert a country code into the HTML on response. (Dynamic)

If having the country code is a nice-to-have and the web page doesn’t need it immediately, then the first approach is a good option. The page can be static and the API call can fail gracefully if it doesn’t work. However, if the country code is required for the page, dynamically adding it using an edge function might make more sense. It’ll be faster as you don’t need to perform a second request/response cycle.

The key is understanding the problem you’re solving and thinking through the trade-offs you’re making with different approaches. You might end up with the majority of your site Jamstack and a portion dynamic. That’s totally fine and might be necessary for your use case. Typically, the closer you can get to static, the faster, more secure, and more scalable your site will be.

This is only the beginning of the discussion, and I’d love to hear your take. Where would you draw the lines? What do static and Jamstack mean to you? Are you sitting on a chair or stool right now?


The post Static vs. Dynamic vs. Jamstack: Where’s The Line? appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Categories: Designing, Others Tags:

Napkin

August 11th, 2021 No comments

We took a surface level look at Pipedream the other day, which really does look cool. It’s like a much more modern and fancy version of what Yahoo Pipes was. A better comparison might be Zapier, except you write code (if you want to) to make easy-to-build cloud functions that can be triggered by anything from RSS to HTTP requests to Slack messages. I wouldn’t say Pipedream itself is complicated to learn (although, admittedly, I haven’t exactly dug deep), but it does embrace complexity. Lots of inputs, lots of processing possibilities, and lots of outputs. Unlimited combinations, you might say.

I saw and bookmarked Napkin.io the other day, which, so far (as it’s brand new) seems to push away the complexity.

Computing tools should be made for humans. They should allow us to be more creative, more free, and more inspired. We believe everyone should have access to computing and tap into its full potential.

We’re making Napkin to change the status quo, to build a new kind of tool – a tool that gets out of your way, that lets you code, and that’s a joy to use.

Philosophy

It’s like a cleaner version of how I remember Webtask. You write a function and… that’s it. It’s available at a URL you can hit.

Each function has environment variables, so you can chuck API keys in there for proxying, auth if you need it, logs for debugging, plus you can write in Node or Python. It’s a healthy amount of features, with more on the way, but it really does feel like embracing simplicity rather than complexity.

Direct Link to ArticlePermalink


The post Napkin appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Categories: Designing, Others Tags:

View Source (on Mobile)

August 10th, 2021 No comments

Have you ever wished you could see the HTML source of a web page while on a mobile browser, which generally doesn’t offer that feature? If you have a desktop machine around, there are ways, but what I mean is getting the source without anything but the device itself.

The little View Source tool by Neatnik does the trick.

You enter the URL in the little bar to see the source of that URL. Or add the URL to the the tool’s URL itself to link right to it. Here’s CSS-Tricks (without line wrapping and tidyied up!):

Direct Link to ArticlePermalink


The post View Source (on Mobile) appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Categories: Designing, Others Tags: