Archive

Archive for October, 2021

The CSS-in-React Landscape

October 21st, 2021 No comments

(This is a sponsored post.)

I only half-jokingly refer to the CSS-in-JS world as CSS-in-React. Many of the libraries listed below theoretically work in non-React situations — they generally call that “framework-agnostic”) — but I’d guess the vast majority of their usage is on React projects. That’s because React, despite being a UI-focused library, has no particular blessed styling solution. Vue has style tags built right into Single File Components. Same with Svelte. Angular also has a built-in component-scoped styles solution. With React, it’s bring-your-own.

Perhaps not venturing too far out of their core strengths is a strength of React. I dunno. But you do have to make a choice on how to style things on your React projects. For example, you can simply write (and there is literally no problem with this), regular ol’ flat-file vanilla CSS to style your React projects. I’d recommend that over using inline style={{ }} on everything any day. But truth be told, there are some pretty nice advantages to choosing a library to help with styles. Things like:

  • Co-locating styles and components
  • Scoping styles to components
  • Using props in styling variations
  • Using JavaScript abilities within CSS syntax
  • Theming

Each library has its own set of fancy things that might be variations on the above, or might be totally unique to that library.

It’s also notable that by using a library where you author styles in your JavaScript, it’s not a 100% guarantee that you have to ship your styles in JavaScript. The libraries that use the term “zero runtime” are typically referring to the idea that the styles are compiled to CSS during a build process, so you use that CSS like any other, which is likely better for performance.

This research is brought to you by support from Frontend Masters, CSS-Tricks’ official learning partner.

Need front-end development training?

Frontend Masters is the best place to get it. They have courses on all the most important front-end technologies, including a Front-End Developer Learning Roadmap that can help you on your journey, which includes a section on CSS in JavaScript.

A couple of caveats before we go through the list:

  • I’m not deeply experienced in every single one of these libraries. I’ve used several of them on real projects, most heavily CSS Modules. I can’t quite speak to the nuances of each. The demos below are basic demonstrations of basic styntax.
  • If I get any facts wrong or you want to add more detail, hit me in the comments or via our contact form and I’ll improve things.
  • The point of this, partially, is to have a working code example of each for easy reference.

styled-components

  • Super popular — probably the most-used option.
  • Popularized the possibilities of dynamic styling and the magic of using props for variations.
  • Template literal syntax feels comfortably CSS-like. It seems like it really encourages using it that way, but it is possible (docs) to use Object syntax.
  • Supports SSR, but it’s not the same as “zero runtime” libraries (which means “compiles to static CSS.” It still ships a JavaScript runtime for any dynamic styles.
CodePen Embed Fallback

CSS Modules

  • Very simple. All it does is scope styles and encourage co-location of styles and components.
  • It’s fancy feature is composition, which is basically mixins based on existing classes.
  • Not a runtime thing at all — it requires a build process. But it still works with HMR and such. You can ship it with styles in JavaScript, or extract them into static CSS files. It does nothing dynamic, so it’s extremely “zero runtime” if you extract the CSS.
  • Can be combined with Sass.
  • Built into Next.js

Emotion

Emotion is a library designed for writing css styles with JavaScript. It provides powerful and predictable style composition in addition to a great developer experience with features such as source maps, labels, and testing utilities. Both string and object styles are supported.

  • It doesn’t seem terribly different than styled-components, TBQH, but this podcast gets into some of the performance differences.
  • Supports SSR, but is not zero-runtime.
  • Glamorous is totally deprecated (and I suppose Glam and Glamor as well?) in favor of Emotion, so that’s something.
CodePen Embed Fallback

Stitches

  • The Variants API is very useful and well done.
  • The TypeScript editor experience¹.
  • Supports theming and encourages using a design token approach.
  • Utilities allow you to build your own custom shorthands for styling.
  • Supports SSR — and it’s closer to zero-runtime, though not entirely. Also doesn’t seem to actually generate CSS files, rather it has a function that spits out CSS so you can use SSR via a tag (which I can’t imagine is ideal for caching).
  • Here’s a Twitter thread with an honest review. Also see all the reactions to this.
CodePen Embed Fallback

vanilla-extract

  • I’d say vanilla-extract supports SSR but it’s more than that because that’s the only way it is used, unless you opt into specific “runtime” features, like dynamic theming. That’s the meaning of “zero runtime”: it only compiles to static CSS files.
  • The TypeScript editor experience¹. (Also see our recent article.)
  • Variants API, including a Recipes API that is like like the Stiches framework above.
  • Supports a theme and utility-class-like approach via Sprinkles
  • I was gonna put Aphrodite on this list, but the creators of it are moving to vanilla-extract, so it probably isn’t a great choice these days, even though it seems to do pretty much all the same stuff as these other libraries.

JSS

  • Has a React-specific integration
  • Has an extend syntax
  • Plugin architecture
CodePen Embed Fallback

Linaria

  • The OG of “Zero Runtime” CSS-in-JS libraries.
  • Compiles to actual CSS files, but still has a runtime if you do dynamic things (at least I think so).
  • Feels similar to styled-components API-wise.
  • Supports Critical CSS.

Styled JSX

  • Babel plugin, so definitely a build-process thing.
  • Using a tag right in the component at the level of nesting you want to scope to is a clever API.
  • Lack of nesting isn’t great — you have to repeat the selector name a lot.

Goober

  • Goober is notable because it has an awesome name and is a mere 1.25KB, which is like an order of magnitude smaller than anything else.
  • Pretty much the same feature set of styled-components and Emotion.
CodePen Embed Fallback

Interesting resources:

  • Shopify’s research on which library they wanted to switch to.
  • Facebook has something cooking (conference video), but hasn’t open-sourced anything. It’s apparently called “StyleX” — and there is already a library called “Style9” that attempts to match the features, including near-zero runtime, atomic CSS output, and the TypeScript experience.
  • If you’re into authoring in the atomic style, a lot of people think that using Tailwind (probably with just-in-time mode) is the way to go.
  • Probably a more React-y version of Tailwind is Styled System, which provides styles as a bunch of preconfigured props.
  • Twin is along the lines of authoring with atomic styles in a React-y way.
  • I could not get Compiled to work for me. I’m sure it was just me, but I gave up. It looks exactly like the styled-components API to me, except the output is atomic CSS classes, which does seem kinda cool.
  • The site CSS in JS Playground shows a bunch of examples, including a few libraries not mentioned here, like Fela, Radium, and more. My god, are there a lot of these things.
  1. By “the TypeScript editor experience,” I mean the library is written in TypeScript to take advantage of one of TypeScript’s best features: help autocompleting code in code editors. For example, if you’re using VS Code as your code editor, and you write a set of “color” variants, then type <Button color=" in your JSX file, you should get a list of your own compatible variants in the contextual VS Code autocomplete menu to choose from.

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

Categories: Designing, Others Tags:

How to Create a Contact Form With Next.js and Netlify

October 21st, 2021 No comments

We’re going to create a contact form with Next.js and Netlify that displays a confirmation screen and features enhanced spam detection.

Next.js is a powerful React framework for developing performant React applications that scale. By integrating a Next.js site with Netlify’s technology, we can quickly get a working contact form up and running without having to write any server-side code.

Not only is it a relatively fast process to set up forms to be processed by Netlify, but it’s also free to get started (with up to 100 free submissions/per site hosted on Netlify). Form submissions automatically go through Netlify’s built-in spam filter which uses Akismet and there are also options that can be configured to increase the level of spam detection.

Creating the contact form

Within the Next.js application we should create a ContactForm component to render the contact form inside of the contact page. If you’d like for this form to render at /contact, then the ContactForm component below with labels and input fields should be used within the pages/contact.js file.

const ContactForm = (
  <form
    name="contact-form"
    method="POST"
    action="contact/?success=true"
  >
    <label htmlFor="name">Name *</label>
    <input
      id="name"
      name="name"
      required
      type="text"
    />
    <label htmlFor="company">Company *</label>
    <input id="company" name="company" required type="text" />
    <label htmlFor="email">E-mail Address *</label>
    <input id="email" type="email" name="email" required />
    <label htmlFor="message">Message *</label>
    <textarea id="message" name="message" required></textarea>
    <button type="submit">Submit</button>
  </form>
);

The above markup is required to render a form with a field for Name, Company, Email address and message with a submit button. When submitting the form, based on the value of the form’s action, it should redirect to contact/?success=true from /contact. Right now there is not yet a difference between the page’s appearance with and without the success query parameter, but we will update that later.

Our Contact.js file looks like this so far:

import React from "react";
const ContactPage = () => {
 const ContactForm = (/* code in above code sample*/)
 
 return (
   <div>
     <h1>Contact Us</h1>
     {ContactForm}
   </div>
 );
};
 
export default ContactPage;

Now that we have the basic form set up, the real magic will happen after we add additional information for Netlify to auto-recognize the form during future site deployments. To accomplish this we should update the form to have the attribute data-netlify="true" and a hidden input field that contains the name of our contact form. In Netlify, once we navigate to our site in the dashboard and then click on the “forms” tab  we will be able to view our form responses based on the name that we’ve put in our hidden field. It’s important that if you have multiple forms within a site that they have unique names so that they are recorded properly in Netlify.

<form
  method="POST"
  name="contact-form"
  action="contact/?success=true"
  data-netlify="true"
>
<input type="hidden" name="form-name" value="contact-form" />

After successfully deploying the site to Netlify with the data-netlify attribute and the form-name field  then we can go to the deployed version of the site and fill out the form. Upon submitting the form and navigating to https://app.netlify.com/sites/site-name/forms (where site-name is the name of your site) then our most recent form submission should appear if we have successfully set up the form. 

Redirect to confirmation screen 

In order to improve the user experience, we should add some logic to redirect to a confirmation screen on form submission when the URL changes to /contact/?success=true. There is also the option to redirect to an entirely different page as the action when the form is submitted but using query params we can achieve something similar with the Next Router. We can accomplish this by creating a new variable to determine if the confirmation screen or the form should be visible based on the query parameter. The next/router which is imported with import { useRouter } from "next/router"; can be used to retrieve the current query params. 

const router = useRouter();  
const confirmationScreenVisible = router.query?.success && router.query.success === "true";

In our case, the confirmation screen and form can never be visible at the same time; therefore, the following statement can be used to determine if the form is visible or not.

const formVisible = !confirmationScreenVisible; 

To give users the option to resubmit the form, we can add a button to the confirmation screen to reset the form by clearing the query params. Using router.replace (instead of router.push) not only updates the page but replaces the current page in the history to the version without query params. 

<button onClick={() => router.replace("/contact", undefined, { shallow: true })}> Submit Another Response </button>

We can then conditionally render the form based on whether or not the form is visible with:

{formVisible ? ContactForm : ConfirmationMessage}

Putting it all together, we can use the following code to conditionally render the form based on the query params (which are updated when the form is submitted):

import React, { useState } from "react";
import { useRouter } from "next/router";
 
const ContactPage = () => {
 const [submitterName, setSubmitterName] = useState("");
 const router = useRouter();
 const confirmationScreenVisible =
   router.query?.success && router.query.success === "true";
 const formVisible = !confirmationScreenVisible;
 
 const ConfirmationMessage = (
   <React.Fragment>
     <p>
       Thank you for submitting this form. Someone should get back to you within 24-48 hours.
     </p>
 
     <button onClick={() => router.replace("/contact", undefined, { shallow: true })}> Submit Another Response </button>
   </React.Fragment>
 );
 
 const ContactForm = (/* code in first code example */);
 
 return (
   <div>
     <h1>Contact Us</h1>
{formVisible ? ContactForm : ConfirmationMessage}
   </div>
 );
};
 
export default ContactPage;

Adding a hidden bot field

Now that the core functionality of our form is working, we can add additional spam detection to our form in addition to the base spam detection because Akismet is included with all Netlify Forms by default. We can enable this by adding data-netlify-honeypot="bot-field" to our form.

<form
  className="container"
  method="POST"
  name="contact-form"
  action="contact/?success=true"
  data-netlify="true"
  data-netlify-honeypot="bot-field"
>

We also need to create a new hidden paragraph that contains a label named bot-field that contains the input. This field is “visible” to bots, but not humans. When this honeypot form field is filled, Netlify detects a bot and then the submission is flagged as spam.

<p hidden>
  <label>
    Don’t fill this out: <input name="bot-field" />
  </label>
</p>

Further customizations

  • We could explore another spam prevention option that Netlify supports by adding reCAPTCHA 2 to a Netlify form.
  • We could update the form to allow uploaded files with input .
  • We could set up notifications for form submissions. That happens over at https://app.netlify.com/sites/[your-site-name]/settings/forms where we can include a custom subject field (which can be hidden) for email notifications.

Full code

The code for the full site code is available over at GitHub.

 Bonus

The following code includes everything we covered as well as the logic for setting a custom subject line with what was submitted in the name field.

import React, { useState } from "react";
import { useRouter } from "next/router";
 
const ContactPage = () => {
 const [submitterName, setSubmitterName] = useState("");
 const router = useRouter();
 const confirmationScreenVisible =
   router.query?.success && router.query.success === "true";
 const formVisible = !confirmationScreenVisible;
 
 const ConfirmationMessage = (
   <React.Fragment>
     <p>
       Thank you for submitting this form. Someone should get back to you
       within 24-48 hours.
     </p>
 
     <button onClick={() => router.replace("/contact", undefined, { shallow: true })}> Submit Another Response </button>
   </React.Fragment>
 );
 
 const ContactForm = (
   <form
     className="container"
     method="POST"
     name="contact-form"
     action="contact/?success=true"
     data-netlify="true"
     data-netlify-honeypot="bot-field"
   >
     <input
       type="hidden"
       name="subject"
       value={`You've got mail from ${submitterName}`}
     />
     <input type="hidden" name="form-name" value="contact-form" />
     <p hidden>
       <label>
         Don’t fill this out: <input name="bot-field" />
       </label>
     </p>
 
     <label htmlFor="name">Name *</label>
     <input
       id="name"
       name="name"
       required
       onChange={(e) => setSubmitterName(e.target.value)}
       type="text"
     />
     <label htmlFor="company">Company *</label>
     <input id="company" name="company" required type="text" />
     <label htmlFor="email">E-mail Address *</label>
     <input id="email" type="email" name="email" required />
     <label htmlFor="message">Message *</label>
     <textarea id="message" name="message" required/>
     <button type="submit">Submit</button>
   </form>
 );
 
 return (
   <div>
     <h1>Contact Us</h1>
{formVisible ? ContactForm : ConfirmationMessage}
   </div>
 );
};
 
export default ContactPage;

The post How to Create a Contact Form With Next.js and Netlify appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Categories: Designing, Others Tags:

Tilda – The Website Builder That Disrupted The Way We Create Websites

October 21st, 2021 No comments

Tilda website builder combines everything we liked so much about constructors when we were kids – you can experiment, test out and build myriads of new creative ideas out of ready-to-use blocks. Tilda is that type of constructor that allows you to own your creative process and create pretty much any website: landing page, business website, online store, online course with members area, blog, portfolio, or event promo page.

Founded seven years ago, Tilda is a website builder that completely revamped the way we create websites. Tilda has been the first website builder to introduce block mechanics that allows users to create websites out of pre-designed pieces. This breakthrough technology allowed all users – not only designers – to create professional-looking websites. Just like in kid constructors, you can drag-and-drop and mix-and-match blocks on Tilda to let your creativity flow and build a dazzling website, at extraordinary speed. 

When you ask designers why they love Tilda, they usually say it’s because the platform provides the ultimate balance between choosing from templates and being able to fully customize and create from scratch to bring any creative idea to life. Here’s what else they say:

Tilda has been a game-changer for us. It allows our team to quickly spin up new web pages, make edits, and ship new programs. We left WordPress for Tilda and after being with Tilda for 2 years, I don’t ever want to go back.

~ Andy Page, Executive Director, Forge.

I built my first website in 2001. Since then I’ve used countless platforms and website builders for customer websites and my own business. Tilda is the perfect combination of ease of use with powerful features at an unbeatable value.

~ Robby Fowler, Branding and Marketing Strategist, robbyf.com & The Brand ED Podcast.

Let’s dive deeper into core functionalities you can leverage on Tilda. 

#1 Cut Corners With 550+ Pre-Designed Blocks And 210+ Ready-Made Templates

The beauty of Tilda is that it provides 550+ blocks in the ever-growing Block Library designed by professional designers. Thus, you can quickly build a website out of pre-designed blocks that encompass virtually all elements you might need for your website: menu, about us page, features, contact, pricing, etc. 

Customizing each block is a breeze with Tilda: You can drag-and-drop images, edit text right in the layout, alter block height, background color, padding, select the style of buttons, use custom fonts, and assign ready-made animation effects to specific parts of it. Also, Tilda provides a built-in free image library with 600K+ images, so you can find images that are just right for you without leaving Tilda, add them to your website with just one click, and use them for free.

Finally, all blocks fit together so well that it’s almost impossible to create a bad design on Tilda – even if you are a stranger to website building.

For a quick take-off, you can use 210+ ready-made templates for different kinds of websites and projects: online stores, landing pages, webinar promo pages, multimedia articles, blogs, and more. Each template is a sample of modern web design and consists of blocks. It means that templates don’t limit your creativity: you can modify them to your liking by playing with settings, adding extra or removing existing blocks, and embedding images and text. 

Each of the templates and blocks covers over 90% of use cases you’ll ever require and is mobile-ready, meaning that your website will look great on desktop computers, tablets, and smartphones by default.

#2 Jazz Up Your Site With Zero Block: Professional Editor For Web Designers 

To better meet the demands of a creative brief and unleash your creativity, you can use Tilda’s secret weapon called Zero Block. It is a tool for creating uniquely designed blocks on Tilda.

You can control each element of the block, including text, image, button, or background, and decide on their position, size, and screen resolution on which they’ll appear. For example, you can work with layers to create depth with overlay and opacity techniques or set a transparency level on any element and shadow effects below them. Additionally, you can also insert HTML code to add more complex elements, such as calendars, paywall, comments, social media posts, and so much more.  

Finally, Zero Block allows you to fool around with basic and more advanced step-by-step animation for a more individual look. Here’re some animation examples that you can make on Tilda:

Animation on scroll (position of elements is changing on scroll).

Trigger animation (animation is triggered when pointing at or clicking on an object).

Infinite scrolling text.

#3 Import Designs From Figma To Tilda In Minutes

Creators love using Figma for prototyping, but when you have to transfer every element and rebuild your website design from scratch – that’s what’s killing the party. With Tilda, you can easily turn your static designs into an interactive website in no time. 

All it takes is to prepare your Figma design for import with a few easy steps, paste the Figma API token and your layout URL to Tilda, click import and let the magic happen. Once your design is imported, you can bring your project online just by clicking publish.

#4. Make Search Engines Love Your Website With Built-In SEO Optimization

Thanks to the consecutive positioning of blocks on the page, websites designed on Tilda are automatically indexed well by search engines. There is also a set of SEO parameters you can fine-tune right inside the platform to ensure that your web pages rank high even if you don’t have an SEO specialist in-house. These parameters include the title tag, description and keywords meta tags, reader-friendly URLs, H1, H2, and H3 header tags, alt text for images, and easily customizable social media snippets. 

As an additional value, Tilda provides an SEO Assistant that will show you what errors are affecting the indexing of your website and will help test the website for compliance with the search engines’ main recommendations.

#5. Turn Visitors Into Clients

Tilda gives you the power to set up data capture forms and integrate them with 20+ data capture services, such as Google Sheets, Trello, Notion, Salesforce, Monday.com, etc., to ensure seamless lead generation.

For more fun, Tilda developed its CRM to manage your leads better and keep your business organized right inside of a website builder. This is a very easy-to-use tool that automatically adds leads from forms and allows you to manually add leads you captured outside of the website. There is a kanban board that gives you an overall view of how leads are moving through your sales funnel and allows you to move leads between stages easily.

#6. Build A Powerful Online Store In One Day

Tilda provides a set of convenient features to create a remarkable online shopping experience. The platform gives you the power to sell online using ready-made templates or build an online store completely from scratch, add a shopping cart and connect a payment system of choice — Stripe, PayPal, 2Checkout, etc. — to accept online payments in any currency.

If you are looking to run a large ecommerce business, you should also consider Tilda. Thanks to the built-in Product Catalog, you can add up to 5000 items, import and export products in CSV files, easily manage stock, orders, and keep track of store stats.

And thanks to adaptive design, your store will look good across all devices, including tablets and smartphones. 

#7. Bring Your Project Online For Free

Tilda offers three subscription plans: Free, Personal ($10/month with annual subscription), and Business ($20/month with annual subscription). When you sign up for Tilda, you get a lifetime free account. It allows you to publish a website with a free subdomain and gives you access to a selection of blocks and a limited number of features that offer enough to create an impressive website. 

Personal and Business tariffs allow more advanced options, such as connecting custom domains, adding HTML code, receiving payments, and embedding data collection forms. The business plan also allows users to export their website and create five websites (while personal and free plans allow one website per account). 

To discover all features and templates on Tilda, activate a two-week free trial – no credit card required.

Source

The post Tilda – The Website Builder That Disrupted The Way We Create Websites first appeared on Webdesigner Depot.

Categories: Designing, Others Tags:

Respecting Users’ Motion Preferences

October 21st, 2021 No comments

When working with motion on the web, it’s important to consider that not everyone experiences it in the same way. What might feel smooth and slick to some might be annoying or distracting to others — or worse, induce feelings of sickness, or even cause seizures. Websites with a lot of motion might also have a higher impact on the battery life of mobile devices, or cause more data to be used (autoplaying videos, for instance, will require more of a user’s data than a static image). These are just some of the reasons why motion-heavy sites might not be desirable for all.

Most new operating systems enable the user to set their motion preferences in their system-level settings. The prefers-reduced-motion media query (part of the Level 5 Media Queries specification) allows us to detect users’ system-level motion preferences, and apply CSS styles that respect that.

The two options for prefers-reduced-motion are reduce or no-preference. We can use it in the following way in our CSS to turn off an element’s animation if the user has explicitly set a preference for reduced motion:

.some-element {
  animation: bounce 1200ms;
}

@media (prefers-reduced-motion: reduce) {
  .some-element {
    animation: none;
  }
}

Conversely, we could set the animation only if the user has no motion preference. This has the advantage of reducing the amount of code we need to write, and means it’s less likely we’ll forget to cater for users’ motion preferences:

@media (prefers-reduced-motion: no-preference) {
  .some-element {
    animation: bounce 1200ms;
  }
}

An added advantage is that older browsers that don’t support prefers-reduced-motion will ignore the rule and only display our original, motion-free element.

Which Rule?

Unlike min-width and max-width media queries, where the more-or-less established consensus is mobile-first (therefore favoring min-width), there is no single “right” way to write your reduced-motion styles. I tend to favor the second example (applying animations only if prefers-reduced-motion: no-preference evaluates true), for the reasons listed above. Tatiana Mac wrote this excellent article which covers some of the approaches developers might consider taking, as well plenty of other great points, including key questions to ask when designing with motion on the web.

As always, team communication and a consistent strategy are key to ensuring all bases are covered when it comes to web accessibility.

Practical Use: Applying prefers-reduced-motion To Scroll Behavior

prefers-reduced-motion has plenty of applications beyond applying (or not applying) keyframe animations or transitions. One example is smooth scrolling. If we set scroll-behaviour: smooth on our html element, when a user clicks an in-page anchor link they will be smoothly scrolled to the appropriate position on the page (currently not supported in Safari):

html {
  scroll-behavior: smooth;
}

Unfortunately, in CSS we don’t have much control over that behavior right now. If we have a long page of content, the page scrolls very fast, which can be a pretty unpleasant experience for someone with motion sensitivity. By wrapping it in a media query, we can prevent that behavior from being applied in cases where the user has a reduced-motion preference:

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

Catering For Motion Preferences In Javascript

Sometimes we need to apply motion in JavaScript rather than CSS. We can similarly detect a user’s motion preferences with JS, using matchMedia. Let’s see how we can conditionally implement smooth scroll behavior in our JS code:

/* Set the media query */
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)')

button.addEventListener('click', () => {
  /* If the media query matches, set scroll behavior variable to 'auto', 
  otherwise set it to 'smooth' */
  const behavior = prefersReducedMotion.matches ? 'auto' : 'smooth'

  /* When the button is clicked, the user will be scrolled to the top */
  window.scrollTo({
    x: 0,
    y: 0,
    behavior
  })
})

The same principle can be used to detect whether to implement motion-rich UIs with JS libraries — or even whether to load the libraries themselves.

In the following code snippet, the function returns early if the user prefers reduced motion, avoiding the unnecessary import of a large dependency — a performance win for the user. If they have no motion preference set, then we can dynamically import the Greensock animation library and initialize our animations.

const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)')

const loadGSAPAndInitAnimations = () => {
  /* If user prefers reduced motion, do nothing */
  if (prefersReducedMotion.matches) return

  /* Otherwise, import the GSAP module and initialize animations */
  import('gsap').then((object) => {
    const gsap = object.default
    /* Initialize animations with GSAP here */
  })
}

loadGSAPAndInitAnimations()

reduced-motion Doesn’t Mean No Motion

When styling for reduced motion preferences, it’s important that we still provide the user with meaningful and accessible indicators of when an action has occurred. For instance, when switching off a distracting or motion-intensive hover state for users who prefer reduced motion, we must take care to provide a clear alternative style for when the user is hovering on the element.

The following demo shows an elaborate transition when the user hovers or focuses on a gallery item if they have no motion preference set. If they prefer reduced motion, the transition is more subtle, yet still clearly indicates the hover state:

See the Pen Gallery with prefers-reduced-motion by Michelle Barker.

Reduced motion doesn’t necessarily mean removing all transforms from our webpage either. For instance, a button that has a small arrow icon that moves a few pixels on hover is unlikely to cause problems for someone who prefers a reduced-motion experience, and provides a more useful indicator of a change of state than color alone.

I sometimes see developers applying reduced motion styles in the following way, which eliminates all transitions and animations on all elements:

@media screen and (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }
}

This is arguably better than ignoring users’ motion preferences, but doesn’t allow us to easily tailor elements to provide more subtle transitions when necessary.

In the following code snippet, we have a button that grows in scale on hover. We’re transitioning the colors and the scale, but users with a preference for reduced motion will get no transition at all:

button {
  background-color: hotpink;
  transition: color 300ms, background-color 300ms, transform 500ms cubic-bezier(.44, .23, .47, 1.27);
}

button:hover,
button:focus {
  background-color: darkviolet;
  color: white;
  transform: scale(1.2);
}

@media screen and (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }

  button {
    /* Even though we would still like to transition the colors of our button, the following rule will have no effect */
    transition: color 200ms, background-color 200ms;
  }

  button:hover,
  button:focus {
    /* Preventing the button scaling on hover */
    transform: scale(1);
  }
}

Check out this demo to see the effect. This is perhaps not ideal, as the sudden color switch without a transition could feel more jarring than a transition of a couple of hundred milliseconds. This is one reason why, on the whole, I generally prefer to style for reduced motion on a case-by-case basis.

If you’re interested, this is the same demo refactored to allow for customizing the transition when necessary. It uses a custom property for the transition duration, which allows us to toggle the scale transition on and off without having to rewrite the whole declaration.

When Removing Animation Is Better

Eric Bailey raises the point that “not every device that can access the web can also render animation, or render animation smoothly“ in his article, “Revisiting prefers-reduced-motion, the reduced motion media query.” For devices with a low refresh rate, which can cause janky animations, it might in fact be preferable to remove the animation. The update media feature can be used to determine this:

@media screen and
  (prefers-reduced-motion: reduce), 
  (update: slow) {
  * {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

Be sure to read the full article for Eric’s recommendations, as he’s a first-rate person to follow in the field of accessibility.

The Sum Of All Parts

It’s important to keep in mind the overall page design when focusing so tightly on component-level CSS. What might seem a fairly innocuous animation at the component level could have a far greater impact when it’s repeated throughout the page, and is one of many moving parts.

In Tatiana’s article, she suggests organizing animations (with prefers-reduced-motion) in a single CSS file, which can be loaded only if (prefers-reduced-motion: no-preference) evaluates true. Seeing the sum total of all our animations could have the added benefit of helping us visualize the experience of visiting the site as a whole, and tailor our reduced-motion styles accordingly.

Explicit Motion Toggle

While prefers-reduced-motion is useful, it does have the drawback of only catering to users who are aware of the feature in their system settings. Plenty of users lack knowledge of this setting, while others might be using a borrowed computer, without access to system-level settings. Still, others might be happy with the motion for the vast majority of sites, but find sites with heavy use of motion hard to bear.

It can be annoying to have to adjust your system preferences just to visit one site. For these reasons, in some cases, it might be preferable to provide an explicit control on the site itself to toggle motion on and off. We can implement this with JS.

The following demo has several circles drifting around the background. The initial animation styles are determined by the user’s system preferences (with prefers-reduced-motion), however, the user has the ability to toggle motion on or off via a button. This adds a class to the body, which we can use to set styles depending on the selected preference. As a bonus, the choice of motion preference is also preserved in local storage — so it is “remembered” when the user next visits.

See the Pen Reduced-motion toggle by Michelle Barker.

Custom Properties

One feature in the demo is that the toggle sets a custom property, --playState, which we can use to play or pause animations. This could be especially handy if you need to pause or play a number of animations at once. First of all, we set the play state to paused:

.circle {
  animation-play-state: var(--playState, paused);
}

If the user has set a preference for reduced motion in their system settings, we can set the play state to running:

@media (prefers-reduced-motion: no-preference) {
  body {
    --playState: running;
  }
}

Note: Setting this on the body, as opposed to the individual element, means the custom property can be inherited.

When the user clicks the toggle, the custom property is updated on the body, which will toggle any instances where it is used:

// This will pause all animations that use the `--playState` custom property
document.body.style.setProperty('--playState', 'paused')

This might not be the ideal solution in all cases, but one advantage is that the animation simply pauses when the user clicks the toggle, rather than jumping back to its initial state, which could be quite jarring.

Special thanks goes to Scott O’Hara for his recommendations for improving the accessibility of the toggle. He made me aware that some screenreaders don’t announce the updated button text, which is changed when a user clicks the button, and suggested role="switch" on the button instead, with aria-checked toggled to on or off on click.

Video Component

In some instances, toggling motion at the component level might be a better option. Take a webpage with an auto-playing video background. We should ensure the video doesn’t autoplay for users with a preference for reduced motion, but we should still provide a way for them to play the video only if they choose. (Some might argue we should avoid auto-playing videos full stop, but we don’t always win that battle!) Likewise, if a video is set to autoplay for users without a stated preference, we should also provide a way for them to pause the video.

This demo shows how we can set the autoplay attribute when the user has no stated motion preference, implementing a custom play/pause button to allow them to also toggle playback, regardless of preference:

See the Pen Video with motion preference by Michelle Barker.

(I subsequently came upon this post by Scott O‘Hara, detailing this exact use case.)

Using The Element

Chris Coyier wrote an interesting article combining a couple of techniques to load different media sources depending on the user’s motion preferences. This is pretty cool, as it means that for users who prefer reduced motion, the much larger GIF file won’t even be downloaded. The downside, as far as I can see, is that once the file is downloaded, there is no way for the user to switch back to the motion-free alternative.

I create a modified version of the demo which adds this option. (Switch on reduced-motion in your system preferences to see it in action.) Unfortunately, when toggling between the animated and motion-free options in Chrome, it appears the GIF file is downloaded afresh each time, which isn’t the case in other browsers:

See the Pen Prefers Reduction Motion Technique PLUS! [forked] by Michelle Barker.

Still, this technique seems like a more respectful way of displaying GIFs, which can be a source of frustration to users.

Browser Support And Final Thoughts

prefers-reduced-motion has excellent support in all modern browsers going back a couple of years. As we’ve seen, by taking a reduced-motion-first approach, non-supporting browsers will simply get a reduced-motion fallback. There’s no reason not to use it today to make your sites more accessible.

Custom toggles most definitely have a place, and can vastly improve the experience for users who aren’t aware of this setting, or what it does. The downside for the user is inconsistency — if every developer is forced to come up with their own solution, the user needs to look for a motion toggle in a different place on every website.

It feels like the missing layer here is browsers. I’d love to see browsers implement reduced-motion toggles, somewhere easily accessible to the user, so that people know where to find it regardless of the site they’re browsing. It might encourage developers to spend more time ensuring motion accessibility, too.

Related Resources

Categories: Others Tags:

Some Typography Links VIII

October 20th, 2021 No comments


The post Some Typography Links VIII appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Categories: Designing, Others Tags:

@supports selector()

October 19th, 2021 No comments

I didn’t realize the support for @supports determining selector support was so good! I usually think of @supports as a way to test for property: value pair support. But with the selector() function, we can test for selector support as well. It looks like this:

@supports selector(:nth-child(1 of .foo)) {

}

You just drop the selector right between the parens and that’s what it tests for.

That selector above is a pretty good test, actually. It’s a “selector list argument” that works for the :nth-child ‘n’ friends selectors. As I write, it’s only supported in Safari.

So let’s say your ideal situation is that the browser supports this selector. Here’s an example. You know that with

    and

      the only valid child element is

    • . But also say this list needs separators, so you (and I’m not saying this is a great idea) did this kind of thing:

      <ul>
        <li class="list-item">List item</li>
        <li class="list-item">List item</li>
        <li class="separator"></li>
        /* ... */
      </ul>

      Then you also want to zebra-stripe the list. And, if you want zebra striping, you need to select every other .list-item, ignoring the .separator. So…

      li:nth-child(odd of .list-item) {
        background: lightgoldenrodyellow;
      }

      But only Safari supports that… so you can do:

      @supports selector(:nth-child(1 of .foo)) {
        li:nth-child(odd of .list-item) {
          background: lightgoldenrodyellow;
        }
      }

      If you didn’t care what the fallback was, you wouldn’t even have to bother with the @supports at all. But say you do care about the fallback. Perhaps in the supported situation, the zebra striping does the heavy lifting of the UX you are shooting for, so all you need for the seperator is a bit of space. But for non-supporting browsers, you’ll need something beefier because you don’t have the zebra striping.

      So now you can style both situations:

      @supports selector(:nth-child(1 of .foo)) {
        li {
          padding: 0.25em;
        }
        li:nth-child(odd of .list-item) {
          background: lightgoldenrodyellow;
        }
        li.separator {
          list-style: none;
          margin: 0.25em 0;
        }
      }
      @supports not selector(:nth-child(1 of .foo)) {
        li.separator {
          height: 1px;
          list-style: none;
          border-top: 1px dashed purple;
          margin: 0.25em 0;
        }
      }

      If we get the @when syntax, then we can write it a little cleaner:

      /* Maybe? */
      @when supports(selector(:nth-child(1 of .foo))) {
      
      } @else {
      
      }

      Anyway. The end result is…

      Supported
      Not Supported

      There is a JavaScript API for testing support as well. I wasn’t sure if this would actually work, but it appears to! This fails in Chrome and passes in Safari as I write:

      CSS.supports("selector(:nth-child(1 of .foo))")

      While I was putting this together, I was thinking… hmmmmmmm — what CSS selectors are out there that have weird cross-browser support? It’s really not that many. And even of those that do have weird cross-browser support, thinking of the number of use-cases where you care to actually wrap it in an @supports (rather than just let it fail) is fairly few.

      The ::marker pseudo-element would have been a great one, but it’s pretty well supported now. I was thinking the case-insensitive attribute selector, like [href$="pdf" i], would have been a good one, but nope, also well supported. Same deal with the comma-separated :not(a, .b, [c]). Maybe something like :fullscreen / :-webkit-full-screen would be interesting and useful because it’s uniquely not supported in iOS Safari?


      The post @supports selector() appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Categories: Designing, Others Tags:

How to Create a Business Model That Works: 4 Essential Strategies

October 19th, 2021 No comments

There are more than half a billion entrepreneurs in the world. But even though more people are discovering the possibility of starting their own business, the majority don’t see long-term success, with just a third of the companies surviving the first decade.

But despite these odds that may seem unfavorable, almost anyone can start a successful company as long as they follow the best business practices and develop a business model that works consistently.

In fact, the biggest differentiating factor for success might be having a structured approach in running a business and utilizing the new opportunities that become available.

To help you recognize some of these critical aspects of an effective business model, let’s explore a few strategies you should consider below.

Leverage the Potential of Remote Employees

Remote work has become one of the hottest topics of this past year. With the pandemic forcing many businesses to close their offices, the only way to survive was to embrace working from home on a scale much larger than ever before.

But instead of treating it like a challenge, smart entrepreneurs started seeing the immense potential of a more mobile remote workforce. It offers more flexibility, a bigger talent pool, and the ability to save on overhead costs, just to name a few powerful benefits.

And with the help of technology, you can replicate most of the in-office workflows, even things like learning opportunities. For instance, you could put together a virtual lunch and learn, where you introduce an engaging topic during lunch break and keep your remote employees on track professionally.

When you put together a productive and effective remote team, you don’t have to worry about lockdowns, pandemic-related restrictions, or even finding office space. Instead, you can communicate and work with your team from all over the world, which is a business model that’s much more sustainable and resilient.

Be Professional When Communicating With Clients

The initial impressions you make with prospective clients make a big difference. If you present yourself in a professional way, you can start working with solid clients from day one. But poor initial communications can make prospective clients hesitant even if you have a spotless track record.

And a key part of communication is sending strong and thorough proposals. If you use proposal software, you can maintain complete control over the entire process of developing, refining, and tracking your proposals until they are accepted.

By tracking every part of the proposal process, you will continually improve how you negotiate with clients and close deals, learning to emphasize the things your audience cares about the most and differentiating yourself from the competition.

At the same time, you must ensure that all of your employees stay on brand when communicating with clients. Whether it’s support, onboarding, or even sales teams, everyone must know what the clients expect and follow brand guidelines that ensure consistency.

Identify Your Ideal Customer

Any successful business is dependent on its customers. No matter how efficiently you may run the company, it won’t make any difference if you can’t find people interested in what you have to offer.

Therefore, you should make audience research a top priority that you continually revisit as your company moves forward. The better you understand who your ideal customer is and what they prefer, the higher the chance of finding ways to stand out from the competition and build a loyal following for your brand.

As a growing business, you might not have the same marketing budgets as large multinational corporations. But you have the opportunity to focus your approach, identifying the essential products and services your audience cares about. Then, you can cast a smaller net that attracts only the right people, driving sales in the process.

But for any of that to happen, you must first understand who your audience is and what they care about. That includes not just the demographics but also interests, online browsing habits, market awareness, sophistication, and a range of other factors. The more specific you can get, the better long-term outcomes you can expect.

Use Multiple Lead Generation Strategies

Image Source

Once you know who you want to attract, you can start thinking about how to get in front of your best buyers. And that knowledge will be immensely helpful when trying to get the most out of every marketing dollar you spend.

You can run hyper-specific paid advertising campaigns on social media and Google, identifying the ways to attract your ideal customers. You can also write high-quality content around relevant topics and eventually rank for profitable keywords on Google.

Partnering with influencers in your niche is another lucrative opportunity. When you can identify an influencer with an audience that matches yours, even a relatively small following can result in a significant boost in immediate sales.

Bottom Line

Starting a successful business from scratch can be challenging. But if you follow the correct principles and develop a comprehensive business model, it’s possible to attain success even in the most competitive markets.

By leveraging the power of remote workers, sending professional proposals, knowing your audience, and using a variety of lead generation strategies, you can ensure that you always have plenty of leads in the pipeline and can close them at an excellent rate.

Categories: Others Tags:

Smashing Podcast Episode 42 With Jeff Smith: What Is DevOps?

October 19th, 2021 No comments

In this episode, we’re talking about DevOps. What is it, and is it a string to add to your web development bow? Drew McLellan talks to expert Jeff Smith to find out.

Show Notes

Weekly Update

Transcript

Drew McLellan: He’s a DevOps practitioner that focuses on attainable levels of DevOps implementations, regardless of where you are in your journey. He’s director of production operations at digital advertising platform Centro, as well as being a public speaker, sharing his DevOps knowledge with audiences all around the globe. He’s the author of the book, Operations Anti-Patterns, DevOps Solutions for Manning Publishing, which shows how to implement DevOps techniques in the kind of imperfect environments most developers work in. So we know he’s an expert in DevOps, but did you know George Clooney regards him as the best paper airplane maker of a generation? My Smashing friends, please welcome Jeff Smith. Hi Jeff. How are you?

Jeff Smith: I’m smashing, Drew, how you doing?

Drew: I’m good. Thank you. That’s good to hear. So I wanted to talk to you today about the subject of DevOps, which is one of your main key area. Many of our listeners will be involved in web and app development, but maybe only have a loose familiarity with what happens on the operations side of things. I know those of us who might work in larger companies will have whole teams of colleagues who are doing ops. We’re just thankful that whatever it is they do, they’re doing it well. But we hear DevOps mentioned more and more, and it feels like one of those things that as developers, we should really understand. So Jeff, what is DevOps?

Jeff: So if you ask 20 people what DevOps is, you might get 20 different answers. So I will give you my take on it, all right, and know that if you’re at a conference and you mention this, you could get into a fist fight with someone. But for me, DevOps is really about that relationship between, and we focus on dev and ops, but really that inter team relationship and how we go about structuring our work and more importantly, structuring our goals and incentives to make sure that they’re aligned so that we are working towards a common goal. And a lot of the core ideas and concepts from DevOps come from the old world where dev and ops were always adversarial, where there was this constant conflict. And when you think about it, it’s because of the way those two teams are incentivized. One team is incentivized to push changes. Another team is incentivized to keep stability, which means fewer changes.

Jeff: When you do that, you create this inherent conflict and everything spills out from there. So DevOps is really about aligning those teams and goals so that we are working towards a common strategy, but then also adopting practices from both sides, so that dev understands more about ops and ops understands more about dev, as a way to gain and share empathy with each other so that we understand the perspective of where the other person is coming from.

Jeff: But then also to enhance our work. Because again, if I understand your perspective and take that into account in my work, it’s going to be a lot more beneficial for each of us. And there’s a lot that ops can learn from developers in terms of automation and how we go about approaching things so that they’re easily reproducible. So it’s this blending and skills. And what you’re seeing now is that this applies to different group combinations, so you’re hearing things like DevSecOps, DevSecFinOps, DevSecFinHROps. It’s just going to keep growing and growing and growing. So it’s really a lesson that we can stamp out across the organization.

Drew: So it’s taking some of the concepts that we understand as developers and spreading our ideas further into the organization, and at the same time learning what we can from the operations to try and move everyone forward.

Jeff: Absolutely, yes. And another aspect of ops, and you had mentioned it a little bit in the intro, is we think it’s just for these larger organizations with dedicated ops teams and things like that, but one thing to think about is ops is happening in your organization, regardless of the size. It’s just a matter of it’s you doing it, or if there’s a separate team doing it, but somehow you’re deploying code. Somehow you’ve got a server out there running somewhere. So ops exist somewhere in your organization, regardless of the size. The question is, who is doing it? And if it’s a single person or a single group then DevOps might even be even more particularly salient for you, as you need to understand the types of things that ops does.

Drew: As professional developers, how important do you think it is for us to have a good grasp of what DevOps is and what it means to implement?

Jeff: I think it’s super important, especially at this phase of the DevOps journey. And the reason I think it’s important is that one, I think we’re always more efficient, again, when we understand what our counterparts are doing. But the other thing is to be able to take operational concerns into account during your design development and implementation of any technology. So one thing that I’ve learned in my career is that even though I thought developers were masters of the universe and understood everything that had to do with computers, turns out that’s not actually the case. Turns out there’s a lot of things that they outsource to ops in terms of understanding, and sometimes that results in particular design choices or implementation choices that may not be optimal for a production deployment.

Jeff: They might be fine in development and testing and things like that, but once you get to production, it’s a little bit of a different ballgame. So not to say that they need to own that entire set of expertise, but they at least need to know enough to know what they don’t know. So they know when to engage ops early, because that’s a common pattern that we see is development makes a choice. I won’t even say make a choice because they’re not even cognizant that it’s a choice, but there’s something that happens that leads to a suboptimal decision for ops and development was completely unaware. So just having a bit more knowledge about ops, even if it’s just enough to say, maybe we should bring ops in on this to get their perspective before we go moving forward. That could save a lot of time and energy and stability, obviously, as it relates to whatever products you’re releasing.

Drew: I see so many parallels with the way that you’re talking about the relationship between dev and ops as we have between design and dev, where you’ve got designers working on maybe how an interface works and looks and having a good understanding of how that’s actually going to be built in the development role, and bringing developers in to consult can really improve the overall solution just by having that clear communication and an understanding of what each other does. Seems like it’s that same principle played out with DevOps, which is really, really good to hear.

Drew: When I think of the things I hear about DevOps, I hear terms like Kubernetes, Docker, Jenkins, CircleCI. I’ve been hearing about Kubernetes for years. I still don’t have any idea what it is, but from what you’re saying, it seems that DevOps isn’t just about … We’re not just talking about tools here, are we? But more about processes and ways of communicating on workflows, is that right?

Jeff: Absolutely. So my mantra for the last 20 years has always been people process tools. You get people to buy into the vision. From there, you define whatever your process is going to look like to achieve that vision. And then you bring on tools that are going to model whatever your process is. So I always put tools at the tail end of the DevOps conversation, mainly because if you don’t have that buy-in, then it doesn’t matter. I could come up with the greatest continuous deployment pipeline ever, but if people aren’t bought into the idea of shipping every change straight to production, it doesn’t matter, right? What good is the tool? So those tools are definitely part of the conversation, only because they’re a standardized way to meet some common goals that we’ve defined.

Jeff: But you’ve got to make sure that those goals that are being defined make sense for your organization. Maybe continuous deployment doesn’t make sense for you. Maybe you don’t want to ship every single change the minute it comes out. And there are plenty of companies and organizations and reasons why you wouldn’t want to do that. So maybe something like a continuous deployment pipeline doesn’t make sense for you. So while the tools are important, it’s more important to focus on what it is that’s going to deliver value for your organization, and then model and implement the tools that are necessary to achieve that.

Jeff: But don’t go online and find out what everyone’s doing and be like, oh, well, if we’re going to do DevOps, we got to switch to Docker and Kubernetes because that’s the tool chain. No, that’s not it. You may not need those things. Not everyone is Google. Not everyone is Netflix. Stop reading posts from Netflix and Google. Please just stop reading them. Because it gets people all excited and they’re like, well this is what we got to do. And it’s like, well, they’re solving very different problems than the problems that you have.

Drew: So if say I’m starting a new project, maybe I’m a startup business, creating software as a service product. I’ve got three developers, I’ve got an empty Git repo and I’ve got dreams of IPOs. To be all in on a DevOps approach to building this product, what are the names of the building blocks that I should have in place in terms of people and processes and where do I start?

Jeff: So in your specific example, the first place I would start with is punting on most of it as much as possible and using something like Heroku or something to that effect. Because you get so excited about all this AWS stuff, Docker stuff, and in reality, it’s so hard just to build a successful product. The idea that you are focusing on the DevOps portion of it is like, well I would say outsource as much of that stuff as possible until it actually becomes a pain point. But if you’re at that point where you’re saying okay, we’re ready to take this stuff in house and we’re ready to take it to the next level. I would say the first place to start is, where are your pain points? what are the things that are causing you problems?

Jeff: So for some people it’s as simple as automated testing. The idea that hey, we need to run tests every time someone makes a commit, because sometimes we’re shipping stuff that’s getting caught by unit tests that we’ve already written. So then maybe you start with continuous integration. Maybe your deployments are taking hours to complete and they’re very manual, then that’s where you focus and you say like, okay, what automation do we need to be able to make this a one button click affair? But I hate to prescribe a general, this is where you start, just because your particular situation and your particular pain points are going to be different. And the thing is, if it’s a pain point, it should be shouting at you. It should be absolutely shouting at you.

Jeff: It should be one of those things where someone says, oh, what sucks in your organization? And it should be like, oh, I know exactly what that is. So when you approach it from that perspective, I think the next steps become pretty apparent to you in terms of what in the DevOps toolbox you need to unpack and start working with. And then it becomes these minimal incremental changes that just keep coming and you notice that as you get new capabilities, your appetite for substandard stuff becomes very small. So you go from like, oh yeah, deploys take three hours and that’s okay. You put some effort into it and next thing you know, in three weeks, you’re like, man, I cannot believe the deployment is still taking 30 minutes. How do we get this down from 30 minutes? Your appetite becomes insatiable for improvement. So things just sort of spill out from there.

Drew: I’ve been reading your recent book and that highlights what you call the four pillars of DevOps. And none of them is tools, as mentioned, but there are these four main areas of focus, if you like, for DevOps. I noticed that the first one of those is culture, I was quite surprised by that, firstly, because I was expecting you to be talking about tools more and we now understand why, but when it comes to culture, it just seems like a strange thing to have at the beginning. There’s a foundation for a technical approach. How does the culture affect how successful DevOps implementation can be within an organization?

Drew: … how successful DevOps implementation can be within an organization.

Jeff: Culture is really the bedrock of everything when you think about it. And it’s important because culture, and we get into this a little bit deeper in the book, but culture really sets the stage for norms within the organization. Right. You’ve probably been at a company where, if you submitted a PR with no automated testing, that’s not a big thing. People accept it and move on.

Jeff: But then there’s other orgs where that is a cardinal sin. Right. Where if you’ve done that, it’s like, “Whoa, are you insane? What are you doing? There’s no test cases here.” Right. That’s culture though. That is culture that is enforcing that norm to say like, “This is just not what we do.”

Jeff: Anyone can write a document that says we will have automated test cases, but the culture of the organization is what enforces that mechanism amongst the people. That’s just one small example of why culture is so important. If you have an organization where the culture is a culture of fear, a culture of retribution. It’s like if you make a mistake, right, that is sacrilege. Right. That is tantamount to treason. Right.

Jeff: You create behaviors in that organization that are adverse to anything that could be risky or potentially fail. And that ends up leaving a lot of opportunity on the table. Whereas if you create a culture that embraces learning from failure, embraces this idea of psychological safety, where people can experiment. And if they’re wrong, they can figure out how to fail safely and try again. You get a culture of experimentation. You get an organization where people are open to new ideas.

Jeff: I think we’ve all been at those companies where it’s like, “Well, this is just the way it’s done. And no one changes that.” Right. You don’t want that because the world is constantly changing. That’s why we put culture front and center, because a lot of the behaviors within an organization exist because of the culture that exists.

Jeff: And the thing is, cultural actors can be for good or ill. Right. What’s ironic, and we talk about this in the book too, is it doesn’t take as many people as you think to change the organizational culture. Right. Because most people, there’s detractors, and then there’s supporters, and then there’s fence sitters when it comes to any sort of change. And most people are fence sitters. Right. It only takes a handful of supporters to really tip the scales. But in the same sense, it really only takes a handful of detractors to tip the scales either.

Jeff: It’s like, it doesn’t take much to change the culture for the better. And if you put that energy into it, even without being a senior leader, you can really influence the culture of your team, which then ends up influencing the culture of your department, which then ends up influencing the culture of the organization.

Jeff: You can make these cultural changes as an individual contributor, just by espousing these ideas and these behaviors loudly and saying, “These are the benefits that we’re getting out of this.” That’s why I think culture has to be front and fore because you got to get everyone bought into this idea and they have to understand that, as an organization, it’s going to be worthwhile and support it.

Drew: Yeah. It’s got to be a way of life, I guess.

Jeff: Exactly.

Drew: Yeah. I’m really interested in the area of automation because through my career, I’ve never seen some automation that’s been put in place that hasn’t been of benefit. Right. I mean, apart from the odd thing maybe where something’s automated and it goes wrong. Generally, when you take the time to sit down and automate something you’ve been doing manually, it always saves you time and it saves you headspace, and it’s just a weight off your shoulders.

Drew: In taking a DevOps approach, what sort of things would you look to automate within your workflows? And what gains would you expect to see from that over completing things manually?

Jeff: When it comes to automation, to your point, very seldom is there a time where automation hasn’t made life better. Right. The rub that people encounter is finding the time to build that automation. Right. And usually, at my current job, for us it’s actually the point of the request. Right. Because at some point you have to say, “I’m going to stop doing this manually and I’m going to automate it.”

Jeff: And it may have to be the time you get a request where you say, “You know what? This is going to take two weeks. I know we normally turn it around in a couple of hours, but it’s going to take two weeks because this is the request that gets automated.” In terms of identifying what you automate. At Central, I use the process where basically, I would sample all of the different types of requests that came in over a four week period, let’s say. And I would categorize them as planned work, unplanned work, value add work, toil work. Toil being work that’s not really useful, but for some reason, my organization has to do it.

Jeff: And then identifying those things that are like, “Okay, what is the low hanging fruit that we can just get rid of if we were to automate this? What can we do to just simplify this?” And some of the criteria was the risk of the process. Right. Automated database failovers are a little scary because you don’t do them that often. And infrastructure changes. Right. We say, “How often are we doing this thing?” If we’re doing it once a year, it may not be worth automating because there’s very little value in it. But if it’s one of those things that we’re getting two, three times a month, okay, let’s take a look at that. All right.

Jeff: Now, what are the things that we can do to speed this up? And the thing is, when we talk about automation, we instantly jumped to, “I’m going to click a button and this thing’s just going to be magically done.” Right. But there are so many different steps that you can do in automation if you feel queasy. Right. For example, let’s say you’ve got 10 steps with 10 different CLI commands that you would normally run. Your first step of automation could be as simple as, run that command, or at least show that command. Right. Say, “Hey, this is what I’m going to execute. Do you think it’s okay?” “Yes.” “Okay. This is the result I got. Is it okay for me to proceed?” “Yes.” “Okay. This is the result I got.” Right.

Jeff: That way you’ve still got a bit of control. You feel comfortable. And then after 20 executions, you realize you’re just hitting, yes, yes, yes, yes, yes, yes. You say, “All right. Let’s chain all these things together and just make it all one.” It’s not like you’ve got to jump into the deep end of, click it and forget it right off the rip. You can step into this until you feel comfortable.

Jeff: Those are the types of things that we did as part of our automation effort was simply, how do we speed up the turnaround time of this and reduce the level of effort on our part? It may not be 100% day one, but the goal is always to get to 100%. We’ll start with small chunks that we’ll automate parts of it that we feel comfortable with. Yes. We feel super confident that this is going to work. This part we’re a little dicey on, so maybe we’ll just get some human verification before we proceed.

Jeff: The other thing that we looked at in terms of we talk about automation, but is what value are we adding to a particular process? And this is particularly salient for ops. Because a lot of times ops serves as the middleman for a process. Then their involvement is nothing more than some access thing. Right. It’s like, well, ops has to do it because ops is the only person that has access.

Jeff: Well, it’s like, well, how do we outsource that access so that people can do it? Because the reality is, it’s not that we’re worried about developers having production access. Right. We’re worried about developers having unfettered production access. And that’s really a safety thing. Right. It’s like if my toolbox has only sharp knives, I’m going to be very careful about who I give that out to. But if I can mix up the toolbox with a spoon and a hammer so that people can choose the right tool for the job, then it’s a lot easier to loan that out.

Jeff: For example, we had a process where people needed to run ad hoc Ruby scripts in production, for whatever reason. Right. Need to clean up data, need to correct some bad record, whatever. And that would always come through my team. And it’s like, well, we’re not adding any value to this because I can’t approve this ticket. Right. I have no idea. You wrote the software, so what good is it me sitting over your shoulder and going, “Well, I think that’s safe”? Right. I didn’t add any value to typing it in because I’m just typing exactly what you told me to type. Right.

Jeff: And worst case, and at the end of it, I’m really just a roadblock for you because you’re submitting a ticket, then you’re waiting for me to get back from lunch. I’m back from lunch, but I’ve got these other things to work on. We said, “How do we automate this so that we can put this in the hands of developers while at the same time addressing any of these audit concerns that we might have?”

Jeff: We put it in a JIRA workflow, where we had a bot that would automate executing commands that were specified in the JIRA ticket. And then we could specify in the JIRA ticket that it required approval from one of several senior engineers. Right.

Jeff: It makes more sense that an engineer is approving another engineer’s work because they have the context. Right. They don’t have to sit around waiting for ops. The audit piece is answered because we’ve got a clear workflow that’s been defined in JIRA that is being documented as someone approves, as someone requested. And we have automation that is pulling that command and executing that command verbatim in the terminal. Right.

Jeff: You don’t have to worry about me mistyping it. You don’t have to worry about me grabbing the wrong ticket. That increased the turnaround time for those tickets, something like tenfold. Right. Developers are unblocked. My team’s not tied up doing this. And all it really took was a week or two week investment to actually develop the automation and the permissioning necessary to get them access for it.

Jeff: Now we’re completely removed from that. And development is actually able to outsource some of that functionality to lower parts of the organization. They’ve pushed it to customer care. It’s like now when customer care knows that this record needs to be updated for whatever, they don’t need development. They can submit their standard script that we’ve approved for this functionality. And they can run it through the exact same workflow that development does. It’s really a boon all around.

Jeff: And then it allows us to push work lower and lower throughout the organization. Because as we do that, the work becomes cheaper and cheaper because I could have a fancy, expensive developer running this. Right. Or I can have a customer care person who’s working directly with the customer, run it themselves while they’re on the phone with a customer correcting an issue.

Jeff: Automation I think, is key to any organization. And the final point I’ll say on that is, it also allows you to export expertise. Right. Now, I may be the only person that knows how to do this if I needed to do a bunch of commands on the command line. But if I put this in automation, I can give that to anyone. And people know what the end result is, but they don’t need to know all the intermediate steps. I have increased my value tenfold by pushing it out to the organization and taking my expertise and codifying it into something that’s exportable.

Drew: You talked about automating tasks that are occurring frequently. Is there an argument for also automating tasks that happen so infrequently that it takes a developer quite a long time to get back up to speed with how it should work? Because everybody’s forgotten. It’s been so long. It’s been a year, maybe nobody has done it before. Is there an argument for automating those sorts of things too?

Jeff: That’s a tough balancing act. Right. And I always say take it by a case by case basis. And the reason I say that is, one of the mantras in DevOps is if something painful, do it more often. Right. Because the more often you do it, the more muscle memory it becomes and you get to work out and iron out those kinks.

Jeff: The issue that we see with automating very infrequent tasks is that the landscape of the environment tends to change in between executions of that automation. Right. What ends up happening is your code makes particular assumptions about the environment and those assumptions are no longer valid. So the automation ends up breaking anyways.

Drew: And then you’ve got two problems.

Jeff: Right. Right. Exactly. Exactly. And you’re like, “Did I type it wrong? Or is this? No, this thing is actually broke.” So-

Jeff: Typing wrong or is this no, this thing is actually broke. So when it comes to automating infrequent tasks, we really take it by a case by case basis to understand, well, what’s the risk if this doesn’t work, right. If we get it wrong, are we in a bad state or is it just that we haven’t finished this task? So if you can make sure that this would fail gracefully and not have a negative impact, then it’s worth giving a shot in automating it. Because at the very least, then you have a framework of understanding of what should be going on because at the very least, someone’s going to be able to read the code and understand, all right, this is what we were doing. And I don’t understand why this doesn’t work anymore, but I have a clear understanding of what was supposed to happen at least based at design time when this was written.

Jeff: But if you’re ever in a situation where failure could lead to data changes or anything like that, I usually err on the side of caution and keep it manual only because if I have an automation script, if I find some confluence document that’s three years old that says run this script, I tend to have a hundred percent confidence in that script and I execute it. Right. Whereas if it’s a series of manual steps that was documented four years ago, I’m going to be like, I need to do some verification here. Right? Let me step through this a little bit and talk to a few people. And sometimes when we design processes, it’s worthwhile to force that thought process, right? And you have to think about the human component and how they’re going to behave. And sometimes it’s worth making the process a little more cumbersome to force people to think should I be doing this now?

Drew: Are there other ways of identifying what should be automated through sort of monitoring your systems and measuring things? I mean, I think about DevOps and I think about dashboards as one of the things, nice graphs. And I’m sure there’s a lot more to those dashboards than just looking pretty, but it’s always nice to have pretty looking dashboards. Are there ways of measuring what a system’s up to, to help you to make those sorts of decisions?

Jeff: Absolutely. And that sort of segues into the metrics portion of cams, right, is what are the things that we are tracking in our systems to know that they are operating efficiently? And one of the common sort of pitfalls of metrics is we look for errors instead of verifying success. And those are two very different practices, right? So something could flow through the system and not necessarily error out, but not necessarily go through the entire process the way it should. So if we drop a message on a message queue, there should be a corresponding metric that says, “And this message was retrieved and processed,” right? If not, right, you’re going to quickly have an imbalance and the system doesn’t work the way it should. I think we can use metrics as a way to also understand different things that should be automated as we get into those bad states.

Jeff: Right? Because a lot of times it’s a very simple step that needs to be taken to clean things up, right? For people that have been ops for a while, right, the disc space alert, everyone knows about that. Oh, we’re filled up with disc. Oh, we forgot it’s month end and billing ran and billing always fills up the logs. And then VAR log is consuming all the disc space, so we need to run a log rotate. Right? You could get woken up at three in the morning for that, if that’s sort of your preference. But if we sort of know that that’s the behavior, our metrics should be able to give us a clue to that. And we can simply automate the log rotate command, right? Oh, we’ve reached this threshold, execute the log rotate command. Let’s see if the alert clears. If it does, continue on with life. If it doesn’t, then maybe we wake someone up, right.

Jeff: You’re seeing this a lot more with infrastructure automation as well, right, where it’s like, “Hey, are our requests per second are reaching our theoretical maximum. Maybe we need to scale the cluster. Maybe we need to add three or four nodes to the load balancer pool.” And we can do that without necessarily requiring someone to intervene. We can just look at those metrics and take that action and then contract that infrastructure once it goes below a particular threshold, but you got to have those metrics and you got to have those hooks into your monitoring environment to be able to do that. And that’s where the entire metrics portion of the conversation comes in.

Jeff: Plus it’s also good to be able to share that information with other people because once you have data, you can start talking about things in a shared reality, right, because busy is a generic term, but 5,200 requests per second is something much more concrete that we can all reason about. And I think so often when we’re having conversations about capacity or anything, we use these hand-wavy terms, when instead we could be looking at a dashboard and giving very specific values and making sure that everyone has access to those dashboards, that they’re not hidden behind some ops wall that only we have access to for some unknown reason.

Drew: So while sort of monitoring and using metrics as a decision-making tool for the businesses is one aspect of it, it sounds like the primary aspect is having the system monitor itself, perhaps, and to respond maybe with some of these automations as the system as a whole gives itself feedback on onto what’s happening.

Jeff: Absolutely. Feedback loops are a key part of any real system design, right, and understanding the state of the system at any one time. So while it’s easy in the world where everything is working fine, the minute something goes bad, those sorts of dashboards and metrics are invaluable to have, and you’ll quickly be able to identify things that you have not instrumented appropriately. Right. So one of the things that we always talk about in incident management is what questions did you have for the system that couldn’t be answered, right. So what is it, or you’re like, “Oh man, if we only knew how many queries per second were going on right now.” Right.

Jeff: Well, okay. How do we get that for next time? How do we make sure that that’s radiated somewhere? And a lot of times it’s hard when you’re thinking green field to sit down and think of all the data that you might want at any one time. But when you have an incident, it becomes readily apparent what data you wish you had. So it’s important to sort of leverage those incidents and failures and get a better understanding of information that’s missing so that you can improve your incident management process and your metrics and dashboarding.

Drew: One of the problems we sometimes face in development is that teammate members, individual team members hold a lot of knowledge about how a system works and if they leave the company or if they’re out sick or on vacation, that knowledge isn’t accessible to the rest of the team. It seems like the sort of DevOps approach to things is good at capturing a lot of that operational knowledge and building it into systems. So that sort of scenario where an individual has got all the information in their head that doesn’t happen so much. Is that a fair assessment?

Jeff: It is. I think we’ve probably, I think as an industry we might have overstated its efficacy. And the only reason I say that is when our systems are getting so complicated, right? Gone are the days where someone has the entire system in their head and can understand it from beginning to end. Typically, there’s two insidious parts of it. One, people typically focus on one specific area and someone doesn’t have the whole picture, but what’s even more insidious is that we think we understand how the system works. Right. And it’s not until an incident happens that the mental model that we have of the system and the reality of the system come into conflict. And we realize that there’s a divergence, right? So I think it’s important that we continuously share knowledge in whatever form is efficient for folks, whether it be lunch and learns, documentation, I don’t know, presentations, anything like that to sort of share and radiate that knowledge.

Jeff: But we also have to prepare and we have to prepare and define a reality where people may not completely understand how the system works. Right. And the reason I think it’s important that we acknowledge that is because you can make a lot of bad decisions thinking you know how the system behaves and being 100% wrong. Right. So having the wherewithal to understand, okay, we think this is how the system works. We should take an extra second to verify that somehow. Right. I think that’s super important in these complicated environments in these sprawling complex microservice environments. Whereas it can be very, it’s easy to be cavalier if you think, oh yeah, this is definitely how it works. And I’m going to go ahead and shut the service down because everything’s going to be fine. And then everything topples over. So just even being aware of the idea that, you know what, we may not know a hundred percent how this thing works.

Jeff: So let’s take that into account with every decision that we make. I think that’s key. And I think it’s important for management to understand the reality of that as well because for management, it’s easy for us to sit down and say, “Why didn’t we know exactly how this thing was going to fail?” And it’s like, because it’s complicated, right, because there’s 500 touch points, right, where these things are interacting. And if you change one of them, it changes the entire communication pattern. So it’s hard and it’s not getting any easier because we’re getting excited about things like microservices. We’re getting excited about things like Kubernetes. We’re giving people more autonomy and these are just creating more and more complicated interfaces into these systems that we’re managing. And it’s becoming harder and harder for anyone to truly understand them in their entirety.

Drew: We’ve talked a lot about a professional context, big organizations and small organizations too. But I know many of us work on smaller side projects or maybe we volunteer on projects and maybe you’re helping out someone in the community or a church or those sorts of things. Can a DevOps approach benefit those smaller projects or is it just really best left to big organizations to implement?

Jeff: I think DevOps can absolutely benefit those smaller projects. And specifically, because I think sort of some of the benefits that we’ve talked about get amplified in those smaller projects. Right? So exporting of expertise with automation is a big one, right? If I am… Take your church example, I think is a great one, right? If I can build a bunch of automated tests suites to verify that a change to some HTML doesn’t break the entire website, right, I can export that expertise so that I can give it to a content creator who has no technical knowledge whatsoever. Right. They’re a theologian or whatever, and they just want to update a new Bible verse or something, right. But I can export that expertise so that they know that I know when I make this content change, I’m supposed to run this build button.

Jeff: And if it’s green, then I’m okay. And if it’s red, then I know I screwed something up. Right. So you could be doing any manner of testing in there that is extremely complicated. Right. It might even be something as simple as like, hey, there’s a new version of this plugin. And when you deploy, it’s going to break this thing. Right. So it has nothing to do with the content, but it’s at least a red mark for this content creator to say “Oh, something bad happened. I shouldn’t continue. Right. Let me get Drew on the phone and see what’s going on.” Right. And Drew can say, “Oh right. This plugin is upgraded, but it’s not compatible with our current version of WordPress or whatever.” Right. So that’s the sort of value that we can add with some of these DevOps practices, even in a small context, I would say specifically around automation and specifically around some of the cultural aspects too.

Jeff: Right? So I’ve been impressed with the number of organizations that are not technical that are using get to make changes to everything. Right. And they don’t really know what they’re doing. They just know, well, this is what we do. This is the culture. And I add this really detailed commit message here. And then I push it. They are no better than us developers. They know three get commands, but it’s the ones they use over and over and over again. But it’s been embedded culturally and that’s how things are done. So everyone sort of rallies around that and the people that are technical can take that pattern.

Jeff: … around that and the people that are technical can take that pattern and leverage it into more beneficial things that might even be behind the scenes that they don’t necessarily see. So I think there’s some value, definitely. It’s a matter of how deep you want to go, even with the operations piece, right? Like being able to recreate a WordPress environment locally very easily, with something like Docker. They may not understand the technology or anything, but if they run Docker Compose Up or whatever, and suddenly they’re working on their local environment, that’s hugely beneficial for them and they don’t really need to understand all the stuff behind it. In that case, it’s worthwhile, because again, you’re exporting that expertise.

Drew: We mentioned right at the beginning, sort of putting off as much sort of DevOps as possible. You mentioned using tools like Heroku. And I guess that sort of approach would really apply here on getting started with, with a small project. What sort things can platforms like Heroku offer? I mean, obviously, I know you’re not a Heroku expert or representative or anything, but those sorts of platforms, what sort of tools are they offering that would help in this context?

Jeff: So for one, they’re basically taking that operational context for you and they’re really boiling it down into a handful of knobs and levers, right? So I think what it offers is one, it offers a very clear set of what we call the yellow brick road path, where it’s like, “If you go this route, all of this stuff is going to be handled for you and it’s going to make your life easier. If you want to go another route, you can, but then you got to solve for all this stuff yourself.” So following the yellow brick road route helps because one, they’re probably identifying a bunch of things that you hadn’t even thought of. So if you’re using their database container or technology, guess what? You’re going to get a bunch of their metrics for free. You’re going to get a lot of their alerting for free. You didn’t do anything. You didn’t think anything. It’s just when you need it, it’s there. And it’s like, “Oh wow, that’s super are helpful.”

Jeff: Two, when it comes to performance sizing and flexibility, this becomes very easy to sort of manage because the goal is, you’re a startup that’s going to become wildly successful. You’re going to have hockey stick growth. And the last thing you necessarily really want to be doing is figuring out how to optimize your code for performance, while at the same time delivering new features. So maybe you spend your way out of it. You say, “Well, we’re going to go up to the next tier. I could optimize my query code, but it’s much more efficient for me to be spending time building this next feature that’s going to bring in this new batch of users, so let’s just go up to the next tier,” and you click button and you move on.

Jeff: So being able to sort of spend your way out of certain problems, I think it’s hugely beneficial because tech debt gets a bad rap, but tech debt is no different than any debt. It’s the trade off of acquiring something now and dealing with the pain later. And that’s a strategic decision that you have to make in every organization. So unchecked tech debt is bad, right? But tech debt generally, I think, is a business choice and Heroku and platforms like that enable you to make that choice when it comes to infrastructure and performance.

Drew: You’ve written a book, Operations, Anti-Patterns, DevOps Solutions, for Manning. I can tell it’s packed with years of hard-earned experience. The knowledge sort of just leaps out from the page. And I can tell it’s been a real labor of love. It’s packed full of information. Who’s your sort of intended audience for that book? Is it mostly those who are already working in DevOps, or is it got a broader-

Jeff: It’s got a broader… So one of the motivations for the book was that there were plenty of books for people that we’re already doing DevOps. You know what I mean? So we were kind of talking to ourselves and high-fiving each other, like, “Yeah, we’re so advanced. Awesome.” But what I really wanted to write the book for were people that were sort of stuck in these organizations. I don’t want to use the term stuck. That’s unfair, but are in these organizations that maybe aren’t adopting DevOps practices or aren’t at the forefront of technology, or aren’t necessarily cavalier about blowing up the way they do work today, and changing things.

Jeff: I wanted to write it to them, mainly individual contributors and middle managers to say like, “You don’t need to be a CTO to be able to make these sorts of incremental changes, and you don’t have to have this whole sale revolution to be able to gain some of the benefits of DevOps.” So it was really sort of a love letter to them to say like, “Hey, you can do this in pieces. You can do this yourself. And there’s all of these things that you may not think are related to DevOps because you’re thinking of it as tools and Kubernetes.” Not every organization… If you were for this New York State, like the state government, you’re not going to just come in and implement Kubernetes overnight. Right? But you can implement how teams talk to each other, how they work together, how we understand each other’s problems, and how we can address those problems through automation. Those are things that are within your sphere of influence that can improve your day to day life.

Jeff: So it was really a letter to those folks, but I think there’s enough data in there and enough information for people that are in a DevOps organization to sort of glean from and say like, “Hey, this is still useful for us.” And a lot of people, I think identify quickly by reading the book, that they’re not in a DevOps organization, they just have out a job title change. And that happens quite a bit. So they say like, “Hey, we’re DevOps engineers now, but we’re not doing these sorts of practices that are talked about in this book and how do we get there?”

Drew: So it sounds like your book is one of them, but are there other resources that people looking to get started with DevOps could turn to? Are there good places to learn this stuff?

Jeff: Yeah. I think DevOps For Dummies by Emily Freeman is a great place to start. It really does a great job of sorting of laying out some of the core concepts and ideas, and what it is we’re striving for. So that would be a good place to start, just to sort of get a lay of the land. I think the Phoenix Project is obviously another great source by Gene Kim. And that is great, that sort of sets the stage for the types of issues that not being in a DevOps environment can create. And it does a great job of sort of highlighting these patterns and personalities that occur that we see in all types of organizations over and over again. I think it does a great job of sort of highlighting those. And if you read that book, I think you’re going to end up screaming at the pages saying, “Yes, yes. This. This.” So, that’s another great place.

Jeff: And then from there, diving into any of the DevOps handbook. I’m going to kick myself for saying this, but the Google SRE Handbook was another great place to look. Understand that you’re not Google, so don’t feel like you’ve got to implement everything, but I think a lot of their ideas and strategies are sound for any organization, and are great places where you can sort of take things and say like, “Okay, we’re, we’re going to make our operations environment a little more efficient.” And that’s, I think going to be particularly salient for developers that are playing an ops role, because it does focus on a lot of the sort of programmatic approach to solving some of these problems.

Drew: So, I’ve been learning all about DevOps. What have you been learning about lately, Jeff?

Jeff: Kubernetes, man. Yeah. Kubernetes has been a real sort of source of reading and knowledge for us. So we’re trying to implement that at Centro currently, as a means to sort of further empower developers. We want to take things a step further from where we’re at. We’ve got a lot of automation in place, but right now, when it comes to onboarding a new service, my team is still fairly heavily involved with that, depending on the nature of the service. And we don’t want to be in that line of work. We want developers to be able to take an idea from concept to code to deployment, and do that where the operational expertise is codified within the system. So, as you move through the system, the system is guiding you. So we think Kubernetes is a tool that will help us do that.

Jeff: It’s just incredibly complicated. And it’s a big piece to sort of bite off. So figuring out what do deployments look like? How do we leverage these operators inside Kubernetes? What does CICD look like in this new world? So there’s been a lot of reading, but in this field, you’re constantly learning, right? It doesn’t matter how long you’ve been in it, how long you’ve been doing it, you’re an idiot in some aspect of this field somewhere. So, it’s just something you kind of adapt to

Drew: Well, hats off as I say, even after all these years, although I sort of understand where it sits in the stack, I still really don’t have a clue what Kubernetes is doing.

Jeff: I feel similar sometimes. It feels like it’s doing a little bit of everything, right? It is the DNS of the 21st century.

Drew: If you, the listener, would like to hear more from Jeff, you can find him on Twitter, where he’s at dark and nerdy, and find his book and links to past presentations and blog posts at his site, attainabledevops.com. Thanks for joining us today, Jeff. Did you have any parting words?

Jeff: Just keep learning, just get out there, keep learning and talk to your fellow peers. Talk, talk, talk. The more you can talk to the people that you work with, the better understanding, the better empathy you’ll generate for them, and if there’s someone in particular in the organization you hate, make sure you talk to them first.

Categories: Others Tags:

Three-Digit Browser Versions in March 2022

October 18th, 2021 No comments

This isn’t supposed to be any sort of decision-making based on browser User-Agent Strings. But, ya know, collectively, we do make those decisions.

Karl Dubost notes that there is a significant change coming to them, notably moving the version integer past two digits:

According to the Firefox release calendar, during the first quarter of 2022 (probably March), Firefox Nightly will reach version 100. It will set Firefox stable release version around May 2022 (if it doesn’t change until then).

And Chrome release calendar sets a current date of March 29, 2022.

So, we’ll be looking at UAs like:

Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:100.0) Gecko/20100101 Firefox/100.0
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36

A bad RegEx will be getting some people for sure. But even string comparison will catch people, as Karl notes:

"80" < "99" // true
"80" < "100" // false
parseInt("80", 10) < parseInt("99", 10) // true
parseInt("80", 10) < parseInt("100", 10) // true

Might wanna search the ol’ codebase for navigator.userAgent and see what you’re doing.


The post Three-Digit Browser Versions in March 2022 appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Categories: Designing, Others Tags:

How to Build a Nearly Headless WordPress Website

October 18th, 2021 No comments

I believe that a traditional WordPress theme should be able to work as effectively as a static site or a headless web app. The overwhelming majority of WordPress websites are built with a good ol’ fashioned WordPress theme. Most of them even have good caching layers, and dependency optimizations that make these sites run reasonably fast. But as developers, we have accomplished ways to create better results for our websites. Using a headless WordPress has allowed many sites to have faster load speeds, better user interactions, and seamless transitions between pages.

The problem? Maintenance. Let me show you another possibility!

Let’s start by defining what I mean by “Traditional” WordPress, “Headless” WordPress, and then “Nearly Headless” WordPress.

Traditional WordPress websites

Traditionally, a WordPress website is built using PHP to render the HTML markup that is rendered on the page. Each time a link is clicked, the browser sends another request to the server, and PHP renders the HTML markup for the site that was clicked.

This is the method that most sites use. It’s the easiest to maintain, has the least complexity in the tech, and with the right server-side caching tools it can perform fairly well. The issue is, since it is a traditional website, it feels like a traditional website. Transitions, effects, and other stylish, modern features tend to be more difficult to build and maintain in this type of site.

Pros:

  1. The site is easy to maintain.
  2. The tech is relatively simple.
  3. There is great compatibility with WordPress plugins.

Cons:

  1. Your site may feel a little dated as society expects app-like experiences in the browser.
  2. JavaScript tends to be a little harder to write and maintain since the site isn’t using a JavaScript framework to control the site’s behavior.
  3. Traditional websites tend to run slower than headless and nearly headless options.

Headless WordPress websites

A headless WordPress website uses modern JavaScript and some kind of server-side RESTful service, such as the WordPress REST API or GraphQL. Instead of building, and rendering the HTML in PHP, the server sends minimal HTML and a big ol’ JavaScript file that can handle rendering any page on the site. This method loads pages much faster, and opens up the opportunity to create really cool transitions between pages, and other interesting things.

No matter how you spin it, most headless WordPress websites require a developer on-hand to make any significant change to the website. Want to install a forms plugin? Sorry, you probably need a developer to set that up. Want to install a new SEO plugin? Nope, going to need a developer to change the app. Wanna use that fancy block? Too bad — you’re going to need a developer first.

Pros:

  1. The website itself will feel modern, and fast.
  2. It’s easy to integrate with other RESTful services outside of WordPress.
  3. The entire site is built in JavaScript, which makes it easier to build complex websites.

Cons:

  1. You must re-invent a lot of things that WordPress plugins do out of the box for you.
  2. This set up is difficult to maintain.
  3. Compared to other options, hosting is complex and can get expensive.

See “WordPress and Jamstack” for a deeper comparison of the differences between WordPress and static hosting.

I love the result that headless WordPress can create. I don’t like the maintenance. What I want is a web app that allows me to have fast load speeds, transitions between pages, and an overall app-like feel to my site. But I also want to be able to freely use the plugin ecosystem that made WordPress so popular in the first place. What I want is something headless-ish. Nearly headless.

I couldn’t find anything that fit this description, so I built one. Since then, I have built a handful of sites that use this approach, and have built the JavaScript libraries necessary to make it easier for others to create their own nearly headless WordPress theme.

Introducing Nearly Headless WordPress

Nearly headless is a web development approach to WordPress that gives you many of the app-like benefits that come with a headless approach, as well as the ease of development that comes with using a traditional WordPress theme. It accomplishes this with a small JavaScript app that will handle the routing and render your site much like a headless app, but has a fallback to load the exact same page with a normal WordPress request instead. You can choose which pages load using the fallback method, and can inject logic into either the JavaScript or the PHP to determine if the page should be loaded like this.

You can see this in action on the demo site I built to show off just what this approach can do.

For example, one of the sites implementing this method uses a learning management system called LifterLMS to sell WordPress courses online. This plugin has built-in e-commerce capabilities, and sets up the interface needed to host and place course content behind a paywall. This site uses a lot of LifterLMS’s built-in functionality to work — and a big part of that is the checkout cart. Instead of re-building this entire page to work inside my app, I simply set it to load using the fallback method. Because of this, this page works like any old WordPress theme, and works exactly as intended as a result — all without me re-building anything.

Pros:

  1. This is easy to maintain, when set-up.
  2. The hosting is as easy as a typical WordPress theme.
  3. The website feels just as modern and fast as a headless website.

Cons:

  1. You always have to think about two different methods to render your website.
  2. There are limited choices for JavaScript libraries that are effective with this method.
  3. This app is tied very closely to WordPress, so using third party REST APIs is more-difficult than headless.

How it works

For something to be nearly headless, it needs to be able to do several things, including:

  1. load a page using a WordPress request,
  2. load a page using JavaScript,
  3. allow pages to be identical, regardless of how they’re rendered,
  4. provide a way to know when to load a page using JavaScript, or PHP, and
  5. Ensure 100% parity on all routed pages, regardless of if it’s rendered with JavaScript or PHP.

This allows the site to make use of progressive enhancement. Since the page can be viewed with, or without JavaScript, you can use whichever version makes the most sense based on the request that was made. Have a trusted bot crawling your site? Send them the non-JavaScript version to ensure compatibility. Have a checkout page that isn’t working as-expected? Force it to load without the app for now, and maybe fix it later.

To accomplish each of these items, I released an open-source library called Nicholas, which includes a pre-made boilerplate.

Keeping it DRY

The biggest concern I wanted to overcome when building a nearly-headless app is keeping parity between how the page renders in PHP and JavaScript. I did not want to have to build and maintain my markup in two different places — I wanted a single source for as much of the markup as possible. This instantly limited which JavaScript libraries I could realistically use (sorry React!). With some research, and a lot of experimentation, I ended up using AlpineJS. This library kept my code reasonably DRY. There’s parts that absolutely have to be re-written for each one (loops, for example), but most of the significant chunks of markup can be re-used.

A single post template rendered with PHP might look like something like this:

<?php
if ( have_posts() ) {
  while ( have_posts() ) {
    the_post();
    if ( is_singular() ) {
      echo nicholas()->templates()->get_template( 'index', 'post', [
        'content' => Nicholas::get_buffer( 'the_content' ),
        'title'   => Nicholas::get_buffer( 'the_title' ),
      ] );
    }
  }
}
?>

That same post template rendered in JavaScript, using Alpine:

<template x-for="(post, index) in $store.posts" :key="index">
  <?= nicholas()->templates()->get_template( 'index', 'post' ) ?>
</template>

Both of them use the same PHP template, so all of the code inside the actual loop is DRY:

$title   = $template->get_param( 'title', '' ); // Get the title that was passed into this template, fallback to empty string.$content = $template->get_param( 'content', '' ); // Get the content passed into this template, fallback to empty string.

?>
<article x-data="theme.Post(index)">
  <!-- This will use the alpine directive to render the title, or if it's in compatibility mode PHP will fill in the title directly -->
  <h1 x-html="title"><?= $title ?></h1>
  <!-- This will use the Alpine directive to render the post content, or if it's in compatibility mode, PHP will fill in the content directly -->
  <div class="content" x-html="content"><?= $content ?></div>
</article>

Related: This Alpine.js approach is similar in spirit to the Vue.js approach covered in “How to Build Vue Components in a WordPress Theme” by Jonathan Land.

Detect when a page should run in compatibility mode

“Compatibility mode” allows you to force any request to load without the JavaScript that runs the headless version of the site. When a page is set to load using compatibility mode, the page will be loaded using nothing but PHP, and the app script never gets enqueued. This allows “problem pages” that don’t work as-expected with the app to run without needing to re-write anything.

There are several different ways you can force a page to run in compatibility mode — some require code, and some don’t. Nicholas adds a toggle to any post type that makes it possible to force a post to load in compatibility mode.

Along with this, you can manually add any URL to force it to load in compatibility mode inside the Nicholas settings.

These are a great start, but I’ve found that I can usually detect when a page needs to load in compatibility mode automatically based on what blocks are stored in a post. For example, let’s say you have Ninja Forms installed on your site, and you want to use the validation JavaScript they provide instead of re-making your own. In this case, you would have to force compatibility mode on any page that has a Ninja Form on it. You could manually go through and add each URL as you need them, or you can use a query to get all of the content that has a Ninja Forms block on the page. Something like this:

add_filter( 'nicholas/compatibility_mode_urls', function ( $urls ) {
  // Filter Ninja Forms Blocks
  $filtered_urls = Nicholas::get_urls_for_query( [
    'post_type' => 'any',
    's' => 'wp:ninja-forms/form', // Find Ninja Forms Blocks
  ] );

  return array_merge( $urls, $filtered_urls );
} );

That automatically adds any page with a Ninja Forms block to the list of URLs that will load using compatibility mode. This is just using WP_Query arguments, so you could pass anything you want here to determine what content should be added to the list.

Extending the app

Under the hood, Nicholas uses a lightweight router that can be extended using a middleware pattern much like how an Express app handles middleware. When a clicked page is routed, the system runs through each middleware item, and eventually routes the page. By default, the router does nothing; however, it comes with several pre-made middleware pieces that allows you to assemble the router however you see-fit.

A basic example would look something like this:

// Import WordPress-specific middleware
import {
  updateAdminBar,
  validateAdminPage,
  validateCompatibilityMode
} from 'nicholas-wp/middlewares'

// Import generic middleware
import {
  addRouteActions,
  handleClickMiddleware,
  setupRouter,
  validateMiddleware
} from "nicholas-router";

// Do these actions, in this order, when a page is routed.
addRouteActions(
  // First, validate the URL
  validateMiddleware,
  // Validate this page is not an admin page
  validateAdminPage,
  // Validate this page doesn't require compatibility mode
  validateCompatibilityMode,
  // Then, we Update the Alpine store
  updateStore,
  // Maybe fetch comments, if enabled
  fetchComments,
  // Update the history
  updateHistory,
  // Maybe update the admin bar
  updateAdminBar
)

// Set up the router. This also uses a middleware pattern.
setupRouter(
  // Setup event listener for clicks
  handleClickMiddleware
)

From here, you could extend what happens when a page is routed. Maybe you want to scan the page for code to highlight, or perhaps you want to change the content of the tag to match the newly routed page. Maybe even introduce a caching layer. Regardless of what you need to-do, adding the actions needed is as simple as using addRouteAction or setupRouter.

Next steps

This was a brief overview of some of the key components I used to implement the nearly headless approach. If you’re interested in going deeper, I suggest that you take my course at WP Dev Academy. This course is a step-by-step guide on how to build a nearly headless WordPress website with modern tooling. I also suggest that you check out my nearly headless boilerplate that can help you get started on your own project.


The post How to Build a Nearly Headless WordPress Website appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Categories: Designing, Others Tags: