Web Standards

Some Industry Podcasts

Css Tricks - Thu, 10/01/2020 - 9:31am
Clearleft made a 6-episode Season One

It’s called The Clearleft Podcast if you can believe that. It gets into new (at least to me) concepts like Design Ops and Design Sprints, which are loaded terms and need nuanced discussion. It’s really well-edited, pulling in clips from relevant talks and such. A cut above the hit-record-hit-stop ‘n’ polish podcasts that I typically do.

If you like Jeremy’s soothing radio voice, he also narrated our Web History series.

Syntax on CSS

The fellas (Wes and Scott) do a good job of covering the landscape of CSS in 2020. I particularly like the pragmatism here, as they poo-poo on nothing, but rather attempt to pair many of the approaches the discuss to particular development situations.

They also had Adam Argyle on the show to talk about how things end up in CSS.

Netlify has a podcast now

It’s called Remotely Interesting. You’d think it would be the all-Jamstack-all-the-time show (which I’d totally listen to) but the gang over there tackles broad topics, talking about stuff like blogging, passion, and communication (in addition to Jamstack-y stuff, of course).

Igalia Chats: Web Ecosystem Health

An episode with a very tough discussion about what is good for the web and what isn’t.

Igalia’s Brian Kardell sits down with Jeremy Keith and Stuart Langridge to chat about rendering engine diversity, history and the health of the web browser ecosystem.

Solving Solved Problems

That’s the name of a blog post by Ahmad Nassri that was discussed in an episode of JS Party. It was sweet to hear the backstory of Amal and Ahmad and all the mutual respect there. It’s also valuable to bask in the classic build vs. buy conversations that all software companies need to take seriously.

Mine

Dave and I have been extremely consistent, publishing new episodes of ShopTalk Show every Monday. And Marie publishes new CodePen Radio episodes every week as well.

The post Some Industry Podcasts appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

The Paper Prototype Rule

Css Tricks - Thu, 10/01/2020 - 4:39am

I’ve been lucky to have worked with some of the best designers in the industry, including Zhenya Rynzhuk, Louis Paquet, Maria de la Paz Vargas, and of course, dozens of the amazing designers at MediaMonks. Many of the projects we’ve worked on require custom animation and guidelines that enable developers to be fully creative and push the limits of what we think is possible with CSS and JavaScript.

Then there are other projects that lack resources. These are the ones that end up becoming an opportunity for us as developers to take the lead on how certain UI elements animate and whether the guidelines we create add up to a great user experience. Those are generally the projects in which a simple trick can help us determine if we’re on the right track.

I just so happen to have a simple trick that has helped me quickly test if my animations hit the mark. I’d like to share it with you now. I call it The Paper Prototype Rule.

The print mindset

Web design (perhaps unconsciously) inherits many things from print design. If you think about it, some of the most basic interactive web patterns, such as accordions or tabs, are just a digital representation of how we physically have stored information in the past.

I suspect the youngest developers in my team have never had to deal with a paper file cabinet in their lives.

Even though the industry has taken a more digital-first mindset and gone beyond the print paradigm in the past decade, we often struggle to get out of that print mentality. As developers, it can feel as though we’ve been wired to animate UI elements in a boring standard way that doesn’t go beyond the reference of moving pieces of paper.

The Paper Prototype Rule

I’ve picked up some tips and best practices in my years working with other folk and have developed them into some simple rules for working with animation. Although I consider the rules more as guidelines or a personal reference, I’ve recently unlocked more value by starting to pass them on to my team.

And it’s thanks to The Paper Prototype Rule which states:

If you can use a paper prototype to recreate the animation, then you probably need to spend more time on it.

The intent is not to overly complicate animations, but embrace the advantages of creating a digital experience that graduates from print concepts. And the principle is pretty simple. Can the animation be prototyped with paper? If yes, we can do better. If no, then we’re on to something.

The Paper Prototype Rule in practice

Don’t get me wrong, paper prototyping has proven to be a great tool for user testing. But we can use the simplicity of its nature to determine when our interactions are just too simple.

Let’s try an example.

Almost every standard website has some sort of navigation. So let’s assume we inherit a design  comp that provides direction for both active and inactive navigation states. Sure, we can do that. It’s not that hard.

CodePen Embed Fallback

Can we replicate this experience with print? Sure can. All it takes is stacking one piece of paper on top of the other. We can do better.

Assuming the comps we received lack any direction for the transition between those the open and closed menu states, we can make the animation a smidge better with the transform property. That alone improves the experience significantly:

CodePen Embed Fallback

Simply sliding the menu’s active state from left-to-right helps the user understand the transition and provides some context for where they are. There is no doubt that the menu is an overlay that covers the page content. That wasn’t apparent before we added the transform. We could say that, with a simple line of CSS, we’re now getting the job done.

So let’s ask ourselves the question: could this interaction be represented in a paper prototype? My immediate response is: yes. This means there’s plenty of room for improvement.

We can use our digital mindset to create something that doesn’t just get the job done, but enhances the experience. We can play around with techniques like fading, masking, parallax, staggering, or simply splitting the menu into different pieces that animate independently. This is the chance to get creative and use our front-end chops to create a uniquely digital experience.

In the spirit of keeping things simple, let’s see how it would look after applying some basic techniques:

CodePen Embed Fallback

There we go! Now we’re starting to veer away from the paper mentality. Can paper slide from left to right? Yes. But can it fade content in and out with an offset animation? Not that I’ve seen!

And, as I said before, there’s much more we can do here. But I think you get the point. You could spend more time playing with the animations to find the “perfect” interaction but that will largely depend on the project. The goal of this rule is to push ourselves away from the print design mindset and embrace the possibilities we have for creating uniquely digital experiences.

Once you start putting the The Paper Prototype Rule into practice as part of your development process, you’ll likely find yourself striving to find the tools to continue to improve your craft. I always recommend reading up on basic animation principles and always being on the look for fresh inspiration from other websites.

So, the next time you’re working on a carousel, modal, or any other interactive component, take a moment to check your animation approach. Does it pass The Paper Prototype Test? 

Header image by J.J. Ying via Unsplash.

The post The Paper Prototype Rule appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

POW

Css Tricks - Wed, 09/30/2020 - 4:44am

As a connoisseur of web trickery, this is a must share:

POW stands for Packaged Offline/online Webpage. It turns out the png format includes ways to save metadata alongside the image file. A powfile has a metadata entry that contains a zip file that contains a full website.

So a PNG file can contain and entire website with multiple resources. Wild. The concept is open-source.

Direct Link to ArticlePermalink

The post POW appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Some New Icon Sets

Css Tricks - Tue, 09/29/2020 - 5:03am

I’ve bookmarked some icon sets lately, partly because I can never find a nice set when I need to. I figured I’d even go the extra mile here and blog them so I can definitely find them later. Aside from being nice, cohesive, and practical sets of icons, I find it interesting that literally all of them:

  • are SVG, and thus easily resizeable
  • are built with rather efficient <path> elements
  • are stroked instead of filled (at least optionally)
  • have a click-to-copy SVG feature on their site
  • are free and open source

Good job, all! Seems like people are coming around to the idea of an SVG icon system where you just… put the SVG in the HTML.

Tabler Icons

Teenyicons Heroicons hola svg

This one is from Mariana Beldi who recently shared how hand-drawing SVG can be so much more efficient than using an illustration tool.

The post Some New Icon Sets appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Make Your Own Dev Tool

Css Tricks - Tue, 09/29/2020 - 5:03am

Amber Wilson on making bookmarklets to help yo-self. She shows off one that injects an accessibility script — I like this approach, as it means you don’t have to maintain the bookmarklet, just the script it links to. Another example runs some code contained right in the link. The result is literally a bookmark in your browser you can click to do something that is useful to you on any site.

Well, I say “any” site, but what I mean is “sites that don’t have a Content Security Policy (CSP)” which is capable of totally blocking inline scripts (and that’s probably the best thing a CSP can do). That’s wonderful for security, but completely stops bookmarklets. The answer is browser extensions. The story with those is getting better as browsers converge on a standard format.

Browser extensions are much harder to write. Someone should make a browser extension that allows you to create arbitrary bookmarklet-ish snippets to run. I found a few attempts at this in a quick search, but nothing that looks particularly nice. Another thought: DevTools has snippets.

Direct Link to ArticlePermalink

The post Make Your Own Dev Tool appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

The Flavors of Object-Oriented Programming (in JavaScript)

Css Tricks - Mon, 09/28/2020 - 10:42am

In my research, I’ve found there are four approaches to Object-Oriented Programming in JavaScript:

  1. Using Constructor functions
  2. Using Classes
  3. Using Objects linking to other objects (OLOO)
  4. Using Factory functions

Which methods should I use? Which one is “the best” way? Here I’ll present my findings along with information that may help you decide which is right for you.

To make that decision, we’re not just going to look at the different flavors but compare conceptual aspects between them:

  1. Classes vs. Factory functions – Inheritance
  2. Classes vs. Factory functions – Encapsulation
  3. Classes vs. Factory functions – this
  4. Classes vs. Factory functions – Event listeners

Let’s start with a foundation of OOP in JavaScript.

What is Object-Oriented Programming?

Object-Oriented Programming is a way of writing code that allows you to create different objects from a common object. The common object is usually called a blueprint while the created objects are called instances.

Each instance has properties that are not shared with other instances. For example, if you have a Human blueprint, you can create human instances with different names.

The second aspect of Object-Oriented Programming is about structuring code when you have multiple levels of blueprints. This is commonly called Inheritance or subclassing.

The third aspect of Object Oriented Programming is about encapsulation where you hide certain pieces of information within the object so they’re not accessible.

If you need more than this brief intro, here’s an article that introduces this aspect of Object-Oriented Programming if you need help with it.

Let’s begin with the basics — an introduction to the four flavors of Object-Oriented Programming.

The four flavors of Object-Oriented Programming

There are four ways to write Object-Oriented Programming in JavaScript. They are:

  1. Using Constructor functions
  2. Using Classes
  3. Using Objects Linking to Other Objects (OLOO)
  4. Using Factory functions
Using Constructor functions

Constructors are functions that contain a this keyword.

function Human (firstName, lastName) { this.firstName = firstName this.lastName = lastName }

this lets you store (and access) unique values created for each instance. You can create an instance with the new keyword.

const chris = new Human('Chris', 'Coyier') console.log(chris.firstName) // Chris console.log(chris.lastName) // Coyier const zell = new Human('Zell', 'Liew') console.log(zell.firstName) // Zell console.log(zell.lastName) // Liew Class syntax

Classes are said to be the “syntactic sugar” of Constructor functions. As in, Classes are an easier way of writing Constructor functions.

There’s serious contention about whether Classes are bad (like this and this). We’re not going to dive into those arguments here. Instead, we’re just going to look at how to write code with Classes and decide whether Classes are better than constructors based on the code we write.

Classes can be written with the following syntax:

class Human { constructor(firstName, lastName) { this.firstName = firstName this.lastName = lastName } }

Notice the constructor function contains the same code as the Constructor syntax above? We need to do this since we want to initialize values into this. (We can skip constructor if we don’t need to initialize values. More on this later under Inheritance).

At first glance, classes seem to be inferior to constructors — there’s more code to write! Hold your horses and don’t form a conclusion at this point. We have a lot more to cover. Classes begin to shine later.

As before, you can create an instance with the new keyword.

const chris = new Human('Chris', 'Coyier') console.log(chris.firstName) // Chris console.log(chris.lastName) // Coyier Objects Linking to Other Objects (OLOO)

OLOO was coined and popularized by Kyle Simpson. In OLOO, you define the blueprint as a normal object. You then use a method (often named init, but that isn’t required in the way constructor is to a Class) to initialize the instance.

const Human = { init (firstName, lastName ) { this.firstName = firstName this.lastName = lastName } }

You use Object.create to create an instance. After creating the instance, you need to run your init function.

const chris = Object.create(Human) chris.init('Chris', 'Coyier') console.log(chris.firstName) // Chris console.log(chris.lastName) // Coyier

You can chain init after Object.create if you returned this inside init.

const Human = { init () { // ... return this } } const chris = Object.create(Human).init('Chris', 'Coyier') console.log(chris.firstName) // Chris console.log(chris.lastName) // Coyier Factory functions

Factory functions are functions that return an object. You can return any object. You can even return a Class instance or OLOO instance — and it’ll still be a valid Factory function.

Here’s the simplest way to create Factory functions:

function Human (firstName, lastName) { return { firstName, lastName } }

You don’t need new to create instances with Factory functions. You simply call the function.

const chris = Human('Chris', 'Coyier') console.log(chris.firstName) // Chris console.log(chris.lastName) // Coyier

Now that we’ve seen these four OOP setup possibilities, let’s look at how you declare properties and methods on each of them so we can get a little better understanding of working with them before getting to the bigger comparisons we’re trying to make.

Declaring properties and methods

Methods are functions declared as an object’s property.

const someObject = { someMethod () { /* ... */ } }

In Object-Oriented Programming, there are two ways to declare properties and methods:

  1. Directly on the instance
  2. In the Prototype

Let’s learn to do both.

Declaring properties and methods with Constructors

If you want to declare a property directly on an instance, you can write the property inside the constructor function. Make sure to set it as the property for this.

function Human (firstName, lastName) { // Declares properties this.firstName = firstName this.lastname = lastName // Declares methods this.sayHello = function () { console.log(`Hello, I'm ${firstName}`) } } const chris = new Human('Chris', 'Coyier') console.log(chris)

Methods are commonly declared on the Prototype because Prototype allows instances to use the same method. It’s a smaller “code footprint.”

To declare properties on the Prototype, you need to use the prototype property.

function Human (firstName, lastName) { this.firstName = firstName this.lastname = lastName } // Declaring method on a prototype Human.prototype.sayHello = function () { console.log(`Hello, I'm ${this.firstName}`) }

It can be clunky if you want to declare multiple methods in a Prototype.

// Declaring methods on a prototype Human.prototype.method1 = function () { /*...*/ } Human.prototype.method2 = function () { /*...*/ } Human.prototype.method3 = function () { /*...*/ }

You can make things easier by using merging functions like Object.assign.

Object.assign(Human.prototype, { method1 () { /*...*/ }, method2 () { /*...*/ }, method3 () { /*...*/ } })

Object.assign does not support the merging of Getter and Setter functions. You need another tool. Here’s why. And here’s a tool I created to merge objects with Getters and Setters.

Declaring properties and methods with Classes

You can declare properties for each instance inside the constructor function.

class Human { constructor (firstName, lastName) { this.firstName = firstName this.lastname = lastName this.sayHello = function () { console.log(`Hello, I'm ${firstName}`) } } }

It’s easier to declare methods on the prototype. You write the method after constructor like a normal function.

class Human (firstName, lastName) { constructor (firstName, lastName) { /* ... */ } sayHello () { console.log(`Hello, I'm ${this.firstName}`) } }

It’s easier to declare multiple methods on Classes compared to Constructors. You don’t need the Object.assign syntax. You just write more functions.

Note: there’s no , between method declarations in a Class.

class Human (firstName, lastName) { constructor (firstName, lastName) { /* ... */ } method1 () { /*...*/ } method2 () { /*...*/ } method3 () { /*...*/ } } Declaring properties and methods with OLOO

You use the same process for declaring properties and methods on an instance. You assign them as a property of this.

const Human = { init (firstName, lastName) { this.firstName = firstName this.lastName = lastName this.sayHello = function () { console.log(`Hello, I'm ${firstName}`) } return this } } const chris = Object.create(Human).init('Chris', 'Coyier') console.log(chris)

To declare methods in the prototype, you write the method like a normal object.

const Human = { init () { /*...*/ }, sayHello () { console.log(`Hello, I'm ${this.firstName}`) } } Declaring properties and methods with Factory functions

You can declare properties and methods directly by including them in the returned object.

function Human (firstName, lastName) { return { firstName, lastName, sayHello () { console.log(`Hello, I'm ${firstName}`) } } }

You cannot declare methods on the Prototype when you use Factory functions. If you really want methods on the prototype, you need to return a Constructor, Class, or OLOO instance. (Don’t do this since it doesn’t make any sense.)

// Do not do this function createHuman (...args) { return new Human(...args) } Where to declare properties and methods

Should you declare properties and methods directly on the instance? Or should you use prototype as much as you can?

Many people take pride that JavaScript is a “Prototypal Language” (which means it uses prototypes). From this statement, you may make the assumption that using “Prototypes” is better.

The real answer is: It doesn’t matter.

If you declare properties and methods on instances, each instance will take up slightly more memory. If you declare methods on Prototypes, the memory used by each instance will decrease, but not much. This difference is insignificant with computer processing power what it is today. Instead, you want to look at how easy it is to write code — and whether it is possible to use Prototypes in the first place.

For example, if you use Classes or OLOO, you’ll be better off using Prototypes since the code is easier to write. If you use Factory functions, you cannot use Prototypes. You can only create properties and methods directly on the instance.

I wrote a separate article on understanding JavaScript Prototypes if you’re interested in finding out more.

Preliminary verdict

We can make a few notes from the code we wrote above. These opinions are my own!

  1. Classes are better than Constructors because its easier to write multiple methods on Classes.
  2. OLOO is weird because of the Object.create part. I gave OLOO a run for a while, but I always forget to write Object.create. It’s weird enough for me not to use it.
  3. Classes and Factry Fufnctions are easiest to use. The problem is that Factory functions don’t support Prototypes. But like I said, this doesn’t really matter in production.

We’re down to two. Should we choose Classes or Factory functions then? Let’s compare them!

Classes vs. Factory functions — Inheritance

To continue the discussion on Classes and Factory functions, we need to understand three more concepts that are tied closely to Object-Oriented Programming.

  1. Inheritance
  2. Encapsulation
  3. this

Let’s start with Inheritance.

What is Inheritance?

Inheritance is a loaded word. Many people in the industry use Inheritance incorrectly, in my opinion. The word “inheritance” is used when you receive things from somewhere. For example:

  • If you get an inheritance from your parents, it means you get money and assets from them.
  • If you inherit genes from your parents, it means you get your genes from them.
  • If you inherit a process from your teacher, it means you get that process from them.

Fairly straightforward.

In JavaScript, Inheritance can mean the same thing: where you get properties and methods from the parent blueprint.

This means all instances actually inherit from their blueprints. They inherit properties and methods in two ways:

  1. by creating a property or method directly upon creating the instance
  2. via the Prototype chain

We discussed how to do both methods in the previous article so refer back to it if you need help seeing these processes in code.

There’s a second meaning for Inheritance in JavaScript — where you create a derivative blueprint from the parent blueprint. This process is more accurately called Subclassing, but people sometimes will call this Inheritance as well.

Understanding Subclassing

Subclassing is about creating a derivative blueprint from a common blueprint. You can use any Object-Oriented Programming flavor to create the Subclass.

We’ll talk about this with the Class syntax first because it’s easier to understand.

Subclassing with Class

When you create a Subclass, you use the extends keyword.

class Child extends Parent { // ... Stuff goes here }

For example, let’s say we want to create a Developer class from a Human class.

// Human Class class Human { constructor (firstName, lastName) { this.firstName = firstName this.lastName = lastName } sayHello () { console.log(`Hello, I'm ${this.firstName}`) } }

The Developer class will extend Human like this:

class Developer extends Human { constructor(firstName, lastName) { super(firstName, lastName) } // Add other methods }

Note: super calls the Human (also called the “parent”) Class. It initiates the constructor from Human. If you don’t need extra initiation code, you can omit constructor entirely.

class Developer extends Human { // Add other methods }

Let’s say a Developer can code. We can add the code method directly to Developer.

class Developer extends Human { code (thing) { console.log(`${this.firstName} coded ${thing}`) } }

Here’s an example of an instance of Developer:

const chris = new Developer('Chris', 'Coyier') console.log(chris) Subclassing with Factory functions

There are four steps to creating Subclasses with Factory functions:

  1. Create a new Factory function
  2. Create an instance of the Parent blueprint
  3. Create a new copy of this instance
  4. Add properties and methods to this new copy

The process looks like this:

function Subclass (...args) { const instance = ParentClass(...args) return Object.assign({}, instance, { // Properties and methods go here }) }

We’ll use the same example — creating a Developer Subclass — to illustrate this process. Here’s the Human factory function:

function Human (firstName, lastName) { return { firstName, lastName, sayHello () { console.log(`Hello, I'm ${firstName}`) } } }

We can create Developer like this:

function Developer (firstName, lastName) { const human = Human(firstName, lastName) return Object.assign({}, human, { // Properties and methods go here }) }

Then we add the code method like this:

function Developer (firstName, lastName) { const human = Human(firstName, lastName) return Object.assign({}, human, { code (thing) { console.log(`${this.firstName} coded ${thing}`) } }) }

Here’s an example of a Developer instance :

const chris = Developer('Chris', 'Coyier') console.log(chris)

Note: You cannot use Object.assign if you use Getters and Setters. You’ll need another tool, like mix. I explain why in this article.

Overwriting the Parent’s method

Sometimes you need to overwrite the Parent’s method inside the Subclass. You can do this by:

  1. Creating a method with the same name
  2. Calling the Parent’s method (optional)
  3. Changing whatever you need in the Subclass’s method

The process looks like this with Classes:

class Developer extends Human { sayHello () { // Calls the parent method super.sayHello() // Additional stuff to run console.log(`I'm a developer.`) } } const chris = new Developer('Chris', 'Coyier') chris.sayHello()

The process looks like this with Factory functions:

function Developer (firstName, lastName) { const human = Human(firstName, lastName) return Object.assign({}, human, { sayHello () { // Calls the parent method human.sayHello() // Additional stuff to run console.log(`I'm a developer.`) } }) } const chris = new Developer('Chris', 'Coyier') chris.sayHello() Inheritance vs. Composition

No talk about Inheritance ever concludes without the mention of Composition. Experts like Eric Elliot often suggests we should favor Composition over Inheritance.

“Favor object composition over class inheritance” the Gang of Four, “Design Patterns: Elements of Reusable Object Oriented Software”

“In computer science, a composite data type or compound data type is any data type which can be constructed in a program using the programming language’s primitive data types and other composite types. […] The act of constructing a composite type is known as composition.” ~ Wikipedia

So let’s give Composition a deeper look and understand what it is.

Understanding Composition

Composition is the act of combining two things into one. It’s about merging things together. The most common (and simplest) way of merging objects is with Object.assign.

const one = { one: 'one' } const two = { two: 'two' } const combined = Object.assign({}, one, two)

The use of Composition can be better explained with an example. Let’s say we already have two Subclasses, a Designer and Developer. Designers can design, while developers can code. Both designers and developers inherit from the Human class.

Here’s the code so far:

class Human { constructor(firstName, lastName) { this.firstName = firstName this.lastName = lastName } sayHello () { console.log(`Hello, I'm ${this.firstName}`) } } class Designer extends Human { design (thing) { console.log(`${this.firstName} designed ${thing}`) } } class Developer extends Designer { code (thing) { console.log(`${this.firstName} coded ${thing}`) } }

Now let’s say you want to create a third Subclass. This Subclass is a mix of a Designer and a Developer — they can design and code. Let’s call it DesignerDeveloper (or DeveloperDesigner, whichever you fancy).

How would you create the third Subclass?

We cannot extend Designer and Developer classes at the same time. This is impossible because we cannot decide which properties come first. This is often called The Diamond Problem.

The Diamond Problem can be easily solved if we do something like Object.assign – where we prioritize one object over the other. If we use the Object.assign approach, we may be able to extend classes like this. But this is not supported in JavaScript.

// Doesn't work class DesignerDeveloper extends Developer, Designer { // ... }

So we need to rely on Composition.

Composition says: Instead of trying to create DesignerDeveloper via Subclassing, let’s create a new object that stores common features. We can then include these features whenever necessary.

In practice, it can look like this:

const skills = { code (thing) { /* ... */ }, design (thing) { /* ... */ }, sayHello () { /* ... */ } }

We can then skip Human altogether and create three different classes based on their skills.

Here’s the code for DesignerDeveloper:

class DesignerDeveloper { constructor (firstName, lastName) { this.firstName = firstName this.lastName = lastName Object.assign(this, { code: skills.code, design: skills.design, sayHello: skills.sayHello }) } } const chris = new DesignerDeveloper('Chris', 'Coyier') console.log(chris)

You can do the same with Developer and Designer.

class Designer { constructor (firstName, lastName) { this.firstName = firstName this.lastName = lastName Object.assign(this, { design: skills.design, sayHello: skills.sayHello }) } } class Developer { constructor (firstName, lastName) { this.firstName = firstName this.lastName = lastName Object.assign(this, { code: skills.code, sayHello: skills.sayHello }) } }

Did you notice we’re creating methods directly on the instance? This is just one option. We can still put methods into the Prototype, but I think the code looks clunky. (It’s as if we’re writing Constructor functions all over again.)

class DesignerDeveloper { constructor (firstName, lastName) { this.firstName = firstName this.lastName = lastName } } Object.assign(DesignerDeveloper.prototype, { code: skills.code, design: skills.design, sayHello: skills.sayHello })

Feel free to use whatever code structure you’re attracted to. The results are kinda the same anyway.

Composition with Factory Functions

Composition with Factory functions is essentially adding the shared methods into the returned object.

function DesignerDeveloper (firstName, lastName) { return { firstName, lastName, code: skills.code, design: skills.design, sayHello: skills.sayHello } } Inheritance and Composition at the same time

Nobody says we can’t use Inheritance and Composition at the same time. We can!

Using the example we’ve ironed out so far, Designer, Developer, and DesignerDeveloper Humans are still humans. They can extend the Human object.

Here’s an example where we use both inheritance and composition with the class syntax.

class Human { constructor (firstName, lastName) { this.firstName = firstName this.lastName = lastName } sayHello () { console.log(`Hello, I'm ${this.firstName}`) } } class DesignerDeveloper extends Human {} Object.assign(DesignerDeveloper.prototype, { code: skills.code, design: skills.design })

And here’s the same thing with Factory functions:

function Human (firstName, lastName) { return { firstName, lastName, sayHello () { console.log(`Hello, I'm ${this.firstName}`) } } } function DesignerDeveloper (firstName, lastName) { const human = Human(firstName, lastName) return Object.assign({}, human, { code: skills.code, design: skills.design } } Subclassing in the real world

One final point about Subclassing vs. Composition. Even though experts have pointed out that Composition is more flexible (and hence more useful), Subclassing still has its merits. Many things we use today are built with the Subclassing strategy.

For example: The click event we know and love is a MouseEvent. MouseEvent is a Subclass of a UIEvent, which in turn is a Subclass of Event.

Another example: HTML Elements are Subclasses of Nodes. That’s why they can use all properties and methods of Nodes.

Preliminary verdict

Classes and Factory functions can both use Inheritance and Composition. Composition seems to be cleaner in Factory functions though, but that’s not a big win over Classes.

We’ll examine Classes and Factory Functions more in detail next.

Classes vs. Factory functions — Encapsulation

We’v looked at the four different Object-Oriented Programming flavors so far. Two of them — Classes and Factory functions — are easier to use compared to the rest.

But the questions remain: Which should you use? And why?

To continue the discussion on Classes and Factory functions, we need to understand three concepts that are tied closely to Object-Oriented Programming:

  1. Inheritance
  2. Encapsulation
  3. this

We just talked about Inheritance. Now let’s talk about Encapsulation.

Encapsulation

Encapsulation is a big word, but it has a simple meaning. Encapsulation is the act of enclosing one thing inside another thing so the thing inside doesn’t leak out. Think about storing water inside a bottle. The bottle prevents water from leaking out.

In JavaScript, we’re interested in enclosing variables (which can include functions) so these variables don’t leak out into the external scope. This means you need to understand scope to understand encapsulation. We’ll go through an explanation, but you can also use this article to beef up your knowledge regarding scopes.

Simple Encapsulation

The simplest form of Encapsulation is a block scope.

{ // Variables declared here won't leak out }

When you’re in the block, you can access variables that are declared outside the block.

const food = 'Hamburger' { console.log(food) }

But when you’re outside the block, you cannot access variables that are declared inside the block.

{ const food = 'Hamburger' } console.log(food)

Note: Variables declared with var don’t respect block scope. This is why I recommend you use let or const to declare variables.

Encapsulating with functions

Functions behave like block scopes. When you declare a variable inside a function, they cannot leak out of that function. This works for all variables, even those declared with var.

function sayFood () { const food = 'Hamburger' } sayFood() console.log(food)

Likewise, when you’re inside the function, you can access variables that are declared outside of that function.

const food = 'Hamburger' function sayFood () { console.log(food) } sayFood()

Functions can return a value. This returned value can be used later, outside the function.

function sayFood () { return 'Hamburger' } console.log(sayFood()) Closures

Closures are an advanced form of Encapsulation. They’re simply functions wrapped in functions.

// Here's a closure function outsideFunction () { function insideFunction () { /* ...*/ } }

Variables declared in outsideFunction can be used in insideFunction.

function outsideFunction () { const food = 'Hamburger' console.log('Called outside') return function insideFunction () { console.log('Called inside') console.log(food) } } // Calls `outsideFunction`, which returns `insideFunction` // Stores `insideFunction` as variable `fn` const fn = outsideFunction() // Calls `insideFunction` fn() Encapsulation and Object-Oriented Programming

When you build objects, you want to make some properties publicly available (so people can use them). But you also want to keep some properties private (so others can’t break your implementation).

Let’s work through this with an example to make things clearer. Let’s say we have a Car blueprint. When we produce new cars, we fill each car up with 50 liters of fuel.

class Car { constructor () { this.fuel = 50 } }

Here we exposed the fuel property. Users can use fuel to get the amount of fuel left in their cars.

const car = new Car() console.log(car.fuel) // 50

Users can also use the fuel property to set any amount of fuel.

const car = new Car() car.fuel = 3000 console.log(car.fuel) // 3000

Let’s add a condition and say that each car has a maximum capacity of 100 liters. With this condition, we don’t want to let users set the fuel property freely because they may break the car.

There are two ways to do prevent users from setting fuel:

  1. Private by convention
  2. Real Private Members
Private by convention

In JavaScript, there’s a practice of prepending underscores to a variable name. This denotes the variable is private and should not be used.

class Car { constructor () { // Denotes that `_fuel` is private. Don't use it! this._fuel = 50 } }

We often create methods to get and set this “private” _fuel variable.

class Car { constructor () { // Denotes that `_fuel` is private. Don't use it! this._fuel = 50 } getFuel () { return this._fuel } setFuel (value) { this._fuel = value // Caps fuel at 100 liters if (value > 100) this._fuel = 100 } }

Users should use the getFuel and setFuel methods to get and set fuel.

const car = new Car() console.log(car.getFuel()) // 50 car.setFuel(3000) console.log(car.getFuel()) // 100

But _fuel is not actually private. It is still a public variable. You can still access it, you can still use it, and you can still abuse it (even if the abusing part is an accident).

const car = new Car() console.log(car.getFuel()) // 50 car._fuel = 3000 console.log(car.getFuel()) // 3000

We need to use real private variables if we want to completely prevent users from accessing them.

Real Private Members

Members here refer to variables, functions, and methods. It’s a collective term.

Private Members with Classes

Classes let you create private members by prepending # to the variable.

class Car { constructor () { this.#fuel = 50 } }

Unfortunately, you can’t use # directly inside a constructor function.

You need to declare the private variable outside the constructor first.

class Car { // Declares private variable #fuel constructor () { // Use private variable this.#fuel = 50 } }

In this case, we can use a shorthand and declare#fuel upfront since we set fuel to 50.

class Car { #fuel = 50 }

You cannot access #fuel outside Car. You’ll get an error.

const car = new Car() console.log(car.#fuel)

You need methods (like getFuel or setFuel) to use the #fuel variable.

class Car { #fuel = 50 getFuel () { return this.#fuel } setFuel (value) { this.#fuel = value if (value > 100) this.#fuel = 100 } } const car = new Car() console.log(car.getFuel()) // 50 car.setFuel(3000) console.log(car.getFuel()) // 100

Note: I prefer Getters and Setters instead of getFuel and setFuel. The syntax is easier to read.

class Car { #fuel = 50 get fuel () { return this.#fuel } set fuel (value) { this.#fuel = value if (value > 100) this.#fuel = 100 } } const car = new Car() console.log(car.fuel) // 50 car.fuel = 3000 console.log(car.fuel) // 100 Private Members with Factory functions

Factory functions create Private Members automatically. You just need to declare a variable like normal. Users will not be able to get that variable anywhere else. This is because variables are function-scoped and hence encapsulated by default.

function Car () { const fuel = 50 } const car = new Car() console.log(car.fuel) // undefined console.log(fuel) // Error: `fuel` is not defined

We can create getter and setter functions to use this private fuel variable.

function Car () { const fuel = 50 return { get fuel () { return fuel }, set fuel (value) { fuel = value if (value > 100) fuel = 100 } } } const car = new Car() console.log(car.fuel) // 50 car.fuel = 3000 console.log(car.fuel) // 100

That’s it! Simple and easy!

Verdict for Encapsulation

Encapsulation with Factory functions are simpler and easier to understand. They rely on the scopes which are a big part of the JavaScript language.

Encapsulation with Classes, on the other hand, requires prepending # to the private variable. This can make things clunky.

We’ll look at the final concept — this to complete the comparison between Classes and Factory functions — in the next section.

Classes vs. Factory Functions — The this variable

this (ha!) is one of the main arguments against using Classes for Object-Oriented Programming. Why? Because this value changes depending on how it is used. It can be confusing for many developers (both new and experienced).

But the concept of this is relatively simple in reality. There are only six contexts in which you can use this. If you master these six contexts, you’ll have no problems using this.

The six contexts are:

  1. In a global context
  2. Inan object construction
  3. In an object property / method
  4. In a simple function
  5. In an arrow function
  6. In an event listener

I covered these six contexts in detail. Give it a read if you need help understanding this.

Note: Don’t shy away from learning to use this. It’s an important concept you need to understand if you intend on mastering JavaScript.

Come back to this article after you’ve solidified your knowledge on this. We’ll have a deeper discussion about using this in Classes and Factory functions.

Back yet? Good. Let’s go!

Using this in Classes

this refers to the instance when used in a Class. (It uses the “In an object property / method” context.) This is why you can set properties and methods on the instance inside the constructor function.

class Human { constructor (firstName, lastName) { this.firstName = firstName this.lastName = lastName console.log(this) } } const chris = new Human('Chris', 'Coyier') Using this in Constructor functions

If you use this inside a function and new to create an instance, this will refer to the instance. This is how a Constructor function is created.

function Human (firstName, lastName) { this.firstName = firstName this.lastName = lastName console.log(this) } const chris = new Human('Chris', 'Coyier')

I mentioned Constructor functions because you can use this inside Factory functions. But this points to Window (or undefined if you use ES6 Modules, or a bundler like webpack).

// NOT a Constructor function because we did not create instances with the `new` keyword function Human (firstName, lastName) { this.firstName = firstName this.lastName = lastName console.log(this) } const chris = Human('Chris', 'Coyier')

Essentially, when you create a Factory function, you should not use this as if it’s a Constructor function. This is one small hiccup people experience with this. I wanted to highlight the problem and make it clear.

Using this in a Factory function

The correct way to use this in a Factory function is to use it “in an object property / method” context.

function Human (firstName, lastName) { return { firstName, lastName, sayThis () { console.log(this) } } } const chris = Human('Chris', 'Coyier') chris.sayThis()

Even though you can use this in Factory functions, you don’t need to use them. You can create a variable that points to the instance. Once you do this, you can use the variable instead of this. Here’s an example at work.

function Human (firstName, lastName) { const human = { firstName, lastName, sayHello() { console.log(`Hi, I'm ${human.firstName}`) } } return human } const chris = Human('Chris', 'Coyier') chris.sayHello()

human.firstName is clearer than this.firstName because human definitely points back to the instance. You know when you see the code.

If you’re used to JavaScript, you may also notice there’s no need to even write human.firstName in the first place! Just firstName is enough because firstName is in the lexical scope. (Read this article if you need help with scopes.)

function Human (firstName, lastName) { const human = { firstName, lastName, sayHello() { console.log(`Hi, I'm ${firstName}`) } } return human } const chris = Human('Chris', 'Coyier') chris.sayHello()

What we covered so far is simple. It’s not easy to decide whether this is actually needed until we create a sufficiently complicated example. So let’s do that.

Detailed example

Here’s the setup. Let’s say we have a Human blueprint. This Human ha firstName and lastName properties, and a sayHello method.

We have a Developer blueprint that’s derived from Human. Developers can code, so they’ll have a code method. Developers also want to proclaim they’re developers, so we need to overwrite sayHello and add I'm a Developer to the console.

We’ll create this example with Classes and Factory functions. (We’ll make an example with this and an example without this for Factory functions).

The example with Classes

First, we have a Human blueprint. This Human has a firstName and lastName properties, as well as a sayHello method.

class Human { constructor (firstName, lastName) { this.firstName = firstName this.lastname = lastName } sayHello () { console.log(`Hello, I'm ${this.firstName}`) } }

We have a Developer blueprint that’s derived from Human. Developers can code, so they’ll have a code method.

class Developer extends Human { code (thing) { console.log(`${this.firstName} coded ${thing}`) } }

Developers also want to proclaim that they’re developers. We need to overwrite sayHello and add I'm a Developer to the console. We do this by calling Human‘s sayHello method. We can do this using super.

class Developer extends Human { code (thing) { console.log(`${this.firstName} coded ${thing}`) } sayHello () { super.sayHello() console.log(`I'm a developer`) } } The example with Factory functions (with this)

Again, first, we have a Human blueprint. This Human has firstName and lastName properties, as well as a sayHello method.

function Human () { return { firstName, lastName, sayHello () { console.log(`Hello, I'm ${this.firstName}`) } } }

Next, we have a Developer blueprint that’s derived from Human. Developers can code, so they’ll have a code method.

function Developer (firstName, lastName) { const human = Human(firstName, lastName) return Object.assign({}, human, { code (thing) { console.log(`${this.firstName} coded ${thing}`) } }) }

Developers also want to proclaim they’re developers. We need to overwrite sayHello and add I'm a Developer to the console.
We do this by calling Human‘s sayHello method. We can do this using the human instance.

function Developer (firstName, lastName) { const human = Human(firstName, lastName) return Object.assign({}, human, { code (thing) { console.log(`${this.firstName} coded ${thing}`) }, sayHello () { human.sayHello() console.log('I\'m a developer') } }) } The example with Factory functions (without this)

Here’s the full code using Factory functions (with this):

function Human (firstName, lastName) { return { firstName, lastName, sayHello () { console.log(`Hello, I'm ${this.firstName}`) } } } function Developer (firstName, lastName) { const human = Human(firstName, lastName) return Object.assign({}, human, { code (thing) { console.log(`${this.firstName} coded ${thing}`) }, sayHello () { human.sayHello() console.log('I\'m a developer') } }) }

Did you notice firstName is available within the lexical scope in both Human and Developer? This means we can omit this and use firstName directly in both blueprints.

function Human (firstName, lastName) { return { // ... sayHello () { console.log(`Hello, I'm ${firstName}`) } } } function Developer (firstName, lastName) { // ... return Object.assign({}, human, { code (thing) { console.log(`${firstName} coded ${thing}`) }, sayHello () { /* ... */ } }) }

See that? This means you can safely omit this from your code when you use Factory functions.

Verdict for this

In simple terms, Classes require this while Factory functions don’t. I prefer Factory functions here because:

  1. The context of this can change (which can be confusing)
  2. The code written with factory functions is shorter and cleaner (since we can use encapsulated variables without writing this.#variable).

Next up is the last section where we build a simple component together with both Classes and Factory functions. You get to see how they differ and how to use event listeners with each flavolr.

Classes vs Factory functions — Event listeners

Most Object-Oriented Programming articles show you examples without event listeners. Those examples can be easier to understand, but they don’t reflect the work we do as frontend developers. The work we do requires event listeners — for a simple reason — because we need to build things that rely on user input.

Since event listeners change the context of this, they can make Classes troublesome to deal with. At the same time, they make Factory functions more appealing.

But that’s not really the case.

The change in this doesn’t matter if you know how to handle this in both Classes and Factory functions. Few articles cover this topic so I thought it would be good to complete this article with a simple component using Object-Oriented Programming flavors.

Building a counter

We’re going to build a simple counter in this article. We’ll use everything you learned in this article — including private variables.

Let’s say the counter contains two things:

  1. The count itself
  2. A button to increase the count

Here’s the simplest possible HTML for the counter:

<div class="counter"> <p>Count: <span>0</span> <button>Increase Count</button> </div> Building the Counter with Classes

To make things simple, we’ll ask users to find and pass the counter’s HTML into a Counter class.

class Counter () { constructor (counter) { // Do stuff } } // Usage const counter = new Counter(document.querySelector('.counter'))

We need to get two elements in the Counter class:

  1. The <span> that contains the count – we need to update this element when the count increases
  2. The <button> – we need to add an event listener to this element class
Counter () { constructor (counter) { this.countElement = counter.querySelector('span') this.buttonElement = counter.querySelector('button') } }

We’ll initialize a count variable and set it to what the countElement shows. We’ll use a private #count variable since the count shouldn’t be exposed elsewhere.

class Counter () { #count constructor (counter) { // ... this.#count = parseInt(countElement.textContent) } }

When a user clicks the <button>, we want to increase #count. We can do this with another method. We’ll name this method increaseCount.

class Counter () { #count constructor (counter) { /* ... */ } increaseCount () { this.#count = this.#count + 1 } }

Next, we need to update the DOM with the new #count. Let’s create a method called updateCount to do this. We will call updateCount from increaseCount:

class Counter () { #count constructor (counter) { /* ... */ } increaseCount () { this.#count = this.#count + 1 this.updateCount() } updateCount () { this.countElement.textContent = this.#count } }

We’re ready to add the event listener now.

Adding the event listener

We will add the event listener to the this.buttonElement. Unfortunately, we cannot use increaseCount as the callback straightaway. You’ll get an error if you try it.

class Counter () { // ... constructor (counter) { // ... this.buttonElement.addEventListener('click', this.increaseCount) } // Methods }

You get an error because this points to buttonElement. (This is the event listener context.) You’ll see the buttonElement if you logged this into the console.

We need to change the value of this back to the instance for increaseCount in order for things to work. There are two ways to do it:

  1. Use bind
  2. Use arrow functions

Most people use the first method (but the second one is easier).

Adding the event listener with bind

bind returns a new function. It lets you change this to the first argument that’s passed. People normally create event listeners by calling bind(this).

class Counter () { // ... constructor (counter) { // ... this.buttonElement.addEventListener('click', this.increaseCount.bind(this)) } // ... }

This works, but it’s not very nice to read. It’s also not beginner-friendly because bind is seen as an advanced JavaScript function.

Arrow functions

The second way is to use arrow functions. Arrow functions work because it preserves the this value to the lexical context.

Most people write methods inside the arrow function callback, like this:

class Counter () { // ... constructor (counter) { // ... this.buttonElement.addEventListener('click', _ => { this.increaseCount() }) } // Methods }

This works, but it is a long way around. There’s actually a shortcut.

You can create increaseCount with arrow functions. If you do this, the this value for increaseCount will be bound to the instance’s value straightaway.

So here’s the code you need:

class Counter () { // ... constructor (counter) { // ... this.buttonElement.addEventListener('click', this.increaseCount) } increaseCount = () => { this.#count = this.#count + 1 this.updateCounter() } // ... } The code

Here’s a complete version of the Class-based code (using arrow functions).

CodePen Embed Fallback Creating the Counter with Factory functions

We’ll do the same thing here. We’ll get users to pass the Counter’s HTML into the Counter factory.

function Counter (counter) { // ... } const counter = Counter(document.querySelector('.counter'))

We need to get two elements from counter — the <span> and the <button>. We can use normal variables (without this) here because they are private variables already. We won’t expose them.

function Counter (counter) { const countElement = counter.querySelector('span') const buttonElement = counter.querySelector('button') }

We will initialize a count variable to the value that’s present in the HTML.

function Counter (counter) { const countElement = counter.querySelector('span') const buttonElement = counter.querySelector('button') let count = parseInt(countElement.textContext) }

We will increase this count variable with an increaseCount method. You can choose to use a normal function here, but I like to create a method to keep things neat and tidy.

function Counter (counter) { // ... const counter = { increaseCount () { count = count + 1 } } }

Finally, we will update the count with an updateCount method. We will also call updateCount from increaseCount.

function Counter (counter) { // ... const counter = { increaseCount () { count = count + 1 counter.updateCount() } updateCount () { increaseCount() } } }

Notice I used counter.updateCount instead of this.updateCount? I like this because counter is clearer compared to this.I also do this because beginners can also make a mistake with this inside Factory functions (which I’ll cover later).

Adding event listeners

We can add event listeners to the buttonElement. When we do this, we can use counter.increaseCount as the callback straight away.

We can do this because we didn’t use this, so it doesn’t matter even if event listeners change the this value.

function Counter (counterElement) { // Variables // Methods const counter = { /* ... */ } // Event Listeners buttonElement.addEventListener('click', counter.increaseCount) } The this gotcha

You can use this in Factory functions. But you need to use this in a method context.

In the following example, if you call counter.increaseCount, JavaScript will also call counter.updateCount. This works because this points to the counter variable.

function Counter (counterElement) { // Variables // Methods const counter = { increaseCount() { count = count + 1 this.updateCount() } } // Event Listeners buttonElement.addEventListener('click', counter.increaseCount) }

Unfortunately, the event listener wouldn’t work because the this value was changed. You’ll need the same treatment as Classes — with bind or arrow functions to — get the event listener working again.

And this leads me to the second gotcha.

Second this gotcha

If you use the Factory function syntax, you cannot create methods with arrow functions. This is because the methods are created in a simple function context.

function Counter (counterElement) { // ... const counter = { // Do not do this. // Doesn't work because `this` is `Window` increaseCount: () => { count = count + 1 this.updateCount() } } // ... }

So, I highly suggest skipping this entirely if you use Factory functions. It’s much easier that way.

The code CodePen Embed Fallback Verdict for event listeners

Event listeners change the value of this, so we must be very careful about using the this value. If you use Classes, I recommend creating event listeners callbacks with arrow functions so you don’t have to use bind.

If you use Factory functions, I recommend skipping this entirely because it may confuse you. That’s it!

Conclusion

We talked about the four flavors of Object-Oriented Programming. They are:

  1. Constructor functions
  2. Classes
  3. OLOO
  4. Factory functions

First, we concluded that Classes and Factory functions are easier to use from a code-related point of view.

Second, we compared how to use Subclasses with Classes and Factory functions. Here, we see creating Subclasses is easier with Classes, but Composition is easier with Factory functions.

Third, we compared Encapsulation with Classes and Factory functions. Here, we see Encapsulation with Factory functions is natural — like JavaScript — while encapsulation with Classes requires you to add a # before variables.

Fourth, we compared the usage of this in Classes and Factory functions. I feel Factory functions win here because this can be ambiguous. Writing this.#privateVariable also creates longer code compared to using privateVariable itself.

Finally, in this article, we built a simple Counter with both Classes and Factory functions. You learned how to add event listeners to both Object-Oriented Programming programming flavors. Here, both flavors work. You just need to be careful whether you use this or not.

That’s it!

I hope this shines some light on Object-Oriented Programming in JavaScript for you. If you liked this article, you may like my JavaScript course, Learn JavaScript, where I explain (almost) everything you need to know about JavaScript in a format as clear and succinct as this.

If you have any questions on JavaScript or front-end development in general, feel free to reach out to me. I’ll see how I can help!

The post The Flavors of Object-Oriented Programming (in JavaScript) appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Linearly Scale font-size with CSS clamp() Based on the Viewport

Css Tricks - Fri, 09/25/2020 - 4:24am

Responsive typography has been tried in the past with a slew of methods such as media queries and CSS calc().

Here, we’re going to explore a different way to linearly scale text between a set of minimum and maximum sizes as the viewport’s width increases, with the intent of making its behavior at different screen sizes more predictable — All in a single line of CSS, thanks to clamp().

The CSS function clamp() is a heavy hitter. It’s useful for a variety of things, but it’s especially nice for typography. Here’s how it works. It takes three values: 

clamp(minimum, preferred, maximum);

The value it returns will be the preferred value, until that preferred value is lower than the minimum value (at which point the minimum value will be returned) or higher than the maximum value (at which point the maximum will be returned).

In this example, the preferred value is 50%. On the left 50% of the 400px viewport is 200px, which is less than the 300px minimum value that gets used instead. On the right, 50% of the 1400px viewport equals 700px, which is greater than the minimum value and lower than the 800px maximum value, so it equates to 700px.

Wouldn’t it just always be the preferred value then, assuming you aren’t being weird and set it between the minimum and maximum? Well, you’re rather expected to use a formula for the preferred value, like:

.banner {   width: clamp(200px, 50% + 20px, 800px); /* Yes, you can do math inside clamp()! */ }

Say you want to set an element’s minimum font-size to 1rem when the viewport width is 360px or below, and set the maximum to 3.5rem when the viewport width is 840px or above. 

In other words:

1rem   = 360px and below Scaled = 361px - 839px 3.5rem = 840px and above

Any viewport width between 361 and 839 pixels needs a font size linearly scaled between 1 and 3.5rem. That’s actually super easy with clamp()! For example, at a viewport width of 600 pixels, halfway between 360 and 840 pixels, we would get exactly the middle value between 1 and 3.5rem, which is 2.25rem.

What we are trying to achieve with clamp() is called linear interpolation: getting intermediate information between two data points.

Here are the four steps to do this:

Step 1

Pick your minimum and maximum font sizes, and your minimum and maximum viewport widths. In our example, that’s 1rem and 3.5rem for the font sizes, and 360px and 840px for the widths.

Step 2

Convert the widths to rem. Since 1rem on most browsers is 16px by default (more on that later), that’s what we’re going to use. So, now the minimum and maximum viewport widths will be 22.5rem and 52.5rem, respectively.

Step 3

Here, we’re gonna lean a bit to the math side. When paired together, the viewport widths and the font sizes make two points on an X and Y coordinate system, and those points make a line.

(22.5, 1) and (52.5, 3.5)

We kinda need that line — or rather its slope and its intersection with the Y axis to be more specific. Here’s how to calculate that:

slope = (maxFontSize - minFontSize) / (maxWidth - minWidth) yAxisIntersection = -minWidth * slope + minFontSize

That gives us a value of 0.0833 for the slope and -0.875 for the intersection at the Y axis.

Step 4

Now we build the clamp() function. The formula for the preferred value is:

preferredValue = yAxisIntersection[rem] + (slope * 100)[vw]

So the function ends up like this:

.header {   font-size: clamp(1rem, -0.875rem + 8.333vw, 3.5rem); }

You can visualize the result in the following demo:

CodePen Embed Fallback

Go ahead and play with it. As you can see, the font size stops growing when the viewport width is 840px and stops shrinking at 360px. Everything in between changes in linear fashion.

What if the user changes the root’s font size?

You may have noticed a little flaw with this whole approach: it only works as long as the root’s font size is the one you think it is — which is 16px in the previous example — and never changes.

We are converting the widths, 360px and 840px, to rem units by dividing them by 16 because that’s what we assume is the root’s font size. If the user has their preferences set to another root font size, say 18px instead of the default 16px, then that calculation is going to be wrong and the text won’t resize the way we’d expect.

There is only one approach we can use here, and it’s (1) making the necessary calculations in code on page load, (2) listening for changes to the root’s font size, and (3) re-calculating everything if any changes take place.

Here’s a useful JavaScript function to do the calculations:

// Takes the viewport widths in pixels and the font sizes in rem function clampBuilder( minWidthPx, maxWidthPx, minFontSize, maxFontSize ) {   const root = document.querySelector( "html" );   const pixelsPerRem = Number( getComputedStyle( root ).fontSize.slice( 0,-2 ) );   const minWidth = minWidthPx / pixelsPerRem;   const maxWidth = maxWidthPx / pixelsPerRem;   const slope = ( maxFontSize - minFontSize ) / ( maxWidth - minWidth );   const yAxisIntersection = -minWidth * slope + minFontSize   return `clamp( ${ minFontSize }rem, ${ yAxisIntersection }rem + ${ slope * 100 }vw, ${ maxFontSize }rem )`; } // clampBuilder( 360, 840, 1, 3.5 ) -> "clamp( 1rem, -0.875rem + 8.333vw, 3.5rem )"

I’m deliberately leaving out how to inject the returned string into the CSS because there are a ton of ways to do that depending on your needs and whether your are using vanilla CSS, a CSS-in-JS library, or something else. Also, there is no native event for font size changes, so we would have to manually check for that. We could use setInterval to check every second, but that could come at a performance cost.

This is more of an edge case. Very few people change their browser’s font size and even fewer are going to change it precisely while visiting your site. But if you want your site to be as responsive as possible, then this is the way to go.

For those who don’t mind that edge case

You think you can live without it being perfect? Then I got something for you. I made a small tool to make make the calculations quick and simple.

All you have to do is plug the widths and font sizes into the tool, and the function is calculated for you. Copy and paste the result in your CSS. It’s not fancy and I’m sure a lot of it can be improved but, for the purpose of this article, it’s more than enough. Feel free to fork and modify to your heart’s content.

How to avoid reflowing text

Having such fine-grained control on the dimensions of typography allows us to do other cool stuff — like stopping text from reflowing at different viewport widths.

This is how text normally behaves.

It has a number of lines at a certain viewport width… …and wraps it’s lines to fit another width

But now, with the control we have, we can make text keep the same number of lines, breaking on the same word always, on whatever viewport width we throw at it.

Viewport width = 400px Viewport width = 740px

So how do we do this? To start, the ratio between font sizes and viewport widths must stay the same. In this example, we go from 1rem at 320px to 3rem at 960px.

320 / 1 = 320 960 / 3 = 320

If we’re using the clampBuilder() function we made earlier, that becomes:

const text = document.querySelector( "p" ); text.style.fontSize = clampBuilder( 320, 960, 1, 3 );

It keeps the same width-to-font ratio. The reason we do this is because we need to ensure that the text has the right size at every width in order for it to be able to keep the same number of lines. It’ll still reflow at different widths but doing this is necessary for what we are going to do next. 

Now we have to get some help from the CSS character (ch) unit because having the font size just right is not enough. One ch unit is the equivalent to the width of the glyph “0” in an element’s font. We want to make the body of text as wide as the viewport, not by setting width: 100% but with width: Xch, where X is the amount of ch units (or 0s) necessary to fill the viewport horizontally.

To find X, we must divide the minimum viewport width, 320px, by the element’s ch size at whatever font size it is when the viewport is 320px wide. That’s 1rem in this case.

Don’t sweat it, here’s a snippet to calculate an element’s ch size:

// Returns the width, in pixels, of the "0" glyph of an element at a desired font size function calculateCh( element, fontSize ) {   const zero = document.createElement( "span" );   zero.innerText = "0";   zero.style.position = "absolute";   zero.style.fontSize = fontSize;   element.appendChild( zero );   const chPixels = zero.getBoundingClientRect().width;   element.removeChild( zero );   return chPixels; }

Now we can proceed to set the text’s width:

function calculateCh( element, fontSize ) { ... } const text = document.querySelector( "p" ); text.style.fontSize = clampBuilder( 320, 960, 1, 3 ); text.style.width = `${ 320 / calculateCh(text, "1rem" ) }ch`; Umm, who invited you to the party, scrollbar?

Whoa, wait. Something bad happened. There’s a horizontal scrollbar screwing things up!

When we talk about 320px, we are talking about the width of the viewport, including the vertical scrollbar. So, the text’s width is being set to the width of the visible area, plus the width of the scrollbar which makes it overflow horizontally.

Then why not use a metric that doesn’t include the width of the vertical scrollbar? We can’t and it’s because of the CSS vw unit. Remember, we are using vw in clamp() to control font sizes. You see, vw includes the width of the vertical scrollbar which makes the font scale along the viewport width including the scrollbar. If we want to avoid any reflow, then the width must be proportional to whatever width the viewport is, including the scrollbar.

So what do we do? When we do this:

text.style.width = `${ 320 / calculateCh(text, "1rem") }ch`;

…we can scale the result down by multiplying it by a number smaller than 1. 0.9 does the trick. That means the text’s width is going to be 90% of the viewport width, which will more than account for the small amount of space taken up by the scrollbar. We can make it narrower by using an even smaller number, like 0.6.

function calculateCh( element, fontSize ) { ... } const text = document.querySelector( "p" ); text.style.fontSize = clampBuilder( 20, 960, 1, 3 ); text.style.width = `${ 320 / calculateCh(text, "1rem" ) * 0.9 }ch`; So long, scrollbar!

You might be tempted to simply subtract a few pixels from 320 to ignore the scrollbar, like this:

text.style.width = `${ ( 320 - 30 ) / calculateCh( text, "1rem" ) }ch`;

The problem with this is that it brings back the reflow issue! That’s because subtracting from 320 breaks the viewport-to-font ratio.

Viewport width = 650px Viewport width = 670px

The width of text must always be a percentage of the viewport width. Another thing to have in mind is that we need to make sure we’re loading the same font on every device using the site. This sounds obvious doesn’t it? Well, here’s a little detail that could throw your text off. Doing something like font-family: sans-serif won’t guarantee that the same font is used in every browser. sans-serif will set Arial on Chrome for Windows, but Roboto on Chrome for Android. Also, the geometry of some fonts may cause reflow even if you do everything right. Monospaced fonts tend to yield the best results. So always make sure your fonts are on point.

Check out this non-reflowing example in the following demo:

CodePen Embed Fallback Non-reflowing text inside a container

All we have to do is now is apply the font size and width to the container instead of the text elements directly. The text inside it will just need to be set to width: 100%. This isn’t necessary in the cases of paragraphs and headings since they’re block-level elements anyway and will fill the width of the container automatically.

CodePen Embed Fallback

An advantage of applying this in a parent container is that its children will react and resize automatically without having to set their font sizes and widths one-by-one. Also, if we need to change the font size of a single element without affecting the others, all we’d have to do is change its font size to any em amount and it will be naturally relative to the container’s font size.

CodePen Embed Fallback

Non-reflowing text is finicky, but it’s a subtle effect that can bring a nice touch to a design!

Wrapping up

To cap things off, I put together a little demonstration of how all of this could look in a real life scenario.

CodePen Embed Fallback

In this final example, you can also change the root font size and the clamp() function will be recalculated automatically so the text can have the right size in any situation.

Even though the target of this article is to use clamp() with font sizes, this same technique could be used in any CSS property that receives a length unit. Now, I’m not saying you should use this everywhere. Many times, a good old font-size: 1rem is all you need. I’m just trying to show you how much control you can have when you need it.

Personally, I believe clamp() is one of the best things to arrive in CSS and I can’t wait to see what other usages people come up with as it becomes more and more widespread!

The post Linearly Scale font-size with CSS clamp() Based on the Viewport appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Web Technologies and Syntax

Css Tricks - Thu, 09/24/2020 - 8:47am

JavaScript has a (newish) feature called optional chaining. Say I have code like:

const name = Data.person.name;

If person happens to not exist on Data, I’m going to get a hard, show-stopping error. With optional chaining, I can write:

const name = Data.person?.name;

Now if person doesn’t exist, name becomes undefined instead of throwing an error. That’s quite useful if you ask me. In a way, it makes for more resilient code, since there is less possibility of a script that entirely bombs out. But there are arguments that it actually makes for less resilient code, because instead of fixing the problem at the root level (bad data), you’re putting a band-aid on the problem.

Jim Nielsen makes the connection to optional chaining and !important in CSS. Errors of “undefined properties” are perhaps the most common of all JavaScript errors and optional chaining is a quick workaround. Styles that don’t cascade the way you want is (maybe?) the most common of all CSS issues and !important is a quick workaround.

Anyone familiar with CSS knows that using !important doesn’t always fix your problems. In fact, it might just cause you more problems. Ditto for optional chaining in JavaScript, it might cause you more problems than it fixes (we just don’t know it yet since it hasn’t been around long enough).

I like that take.

Sweeping negative hot takes about new features are just clickbait silliness, but sometimes there are good things buried in there to think about. I’ll bet optional chaining settles into some nice patterns in JavaScript, just like !important has in CSS to some degree. Most chatter I hear about !important in CSS lately is about how you should use it when you really mean it (not for getting out of a jam).

Direct Link to ArticlePermalink

The post Web Technologies and Syntax appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

The Empty Box

Css Tricks - Wed, 09/23/2020 - 12:34pm

When I was in high school, we learned about “The Black Box” which is concept in theater. If memory serves me right, the approach was a simple and elegant one: that you can take any space, any black box, and make it come to life with a story. I liked the idea that it’s possible to convey anything, tell any story, and create any reality — all in the confines of what equates to a black box, a simple room that requires a curtain and very little else.

It’s an exciting concept. You see something extremely polished like a studio-produced movie. One might think, “No way I could do that.” All the scripts, the actors, the production, animation, set, props, everything. Where do you even begin?

But looking at things through The Black Box model, we distill the movie down to its essence, the story. We can see it as some folks telling a story in a stark, empty room. Take Thor: Ragnarok, a movie I really enjoy. It has incredible special effects, bits of humor, tension, relationships and stories that are well told. Sibling rivalry? Most of us know of or have seen something like that. Someone confronting you and you’d like to escape? We have all likely dealt with a challenge like that.

Those are the stories. The special effects and polished production? Those merely dress up the stories but aren’t necessary to convey the story. But still, how do you get from a black box to a large scale production?

Or, put in a different context: how do we get from an idea to a full-fledged website or app? You see all of these incredible sites around you and could easily fall into a trap of thinking anything you put out needs to meet the same scale and production. But let’s pull the curtain back on that and play with the idea that…

Apps are the box

Programmers are literal creatures, so instead of a “black box,” which has different connotations in tech, I’ll switch it up and call it an “empty box” — even though that also has roots in other metaphors, such as a the “tabula rasa” (clean slate) in art, which is a very similar concept.

If you look at an apps like Notion, Airbnb, or Etsy as newcomers to the industry, the yes, it might seem impossible how you might get from learning basic CRUD operations to working on an application at the same scale, state and complexity as those apps. But what happens if we flip the script? Instead of thinking about building the entire universe from scratch, maybe we start with an empty box, one that only holds the core use case or problem that’s being solved. We can decide what we’re going to create with this small bit of space we have in the world.

It’s a nice way to dial back the scope. Of course, people might use our sites in myriad ways, but when you peel back every usage, every feature, and compare what else is out there, what is the purpose? Sometimes we work at big companies with lots of competing priorities — so many that if you ask different folks, you’ll likely get a wide range of answers. And certainly any app with any level of complexity has to cater to many user needs.

However, I wonder if it might serve us to be able to answer that question with clarity. Particularly when we’re just starting out.

You have an empty box. What can you build in that space? You can engage people all around the world instantly in any way. You can create any interaction. What is that interaction and what is it trying to convey? What is going to make it relatable? What’s going to get the message across?

Forget about all the production and complexity you could build. What’s the purpose you want to convey at the core? What are you most excited about? What the solution to the problem right in front of you?

The post The Empty Box appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Jamstack Conf

Css Tricks - Tue, 09/22/2020 - 8:38am

Here’s an important detail here: It’s free!

Jamstack Conf Virtual is coming up October 6th and 7th, 2020. The sessions are on October 6th. That’s the free part (register here). Then on October 7th there are a variety of workshops (they all look great to me) that are $100 USD each. That’s the classic conference one-two punch. Sessions are for getting a broad sense of what’s happening and will very likely open your eyes to some new concepts; workshops are for deep learning and walking away with some new skills.

The speaker lineup is top-notch!

I’ve been to several Jamstack Conf’s myself, and I’m a fan. Some of my most favorite conferences ever are ones that are focused around a technological idea at the rise of their relevance. That’s exactly what’s happening here and I’m excited to check it out. You can even watch videos from the 2019 conference to see just how awesome of an experience it is.

Direct Link to ArticlePermalink

The post Jamstack Conf appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Accessible Web Animation: The WCAG on Animation Explained

Css Tricks - Tue, 09/22/2020 - 4:56am

It’s true, web animation can be accessible! Sometimes it just takes a little extra effort to make sure that it is. There are strategic things we can do to make sure our animations have a positive impact on accessibility, like planning how they contribute to the overall UX and ease of use of our site. There are also more tactical considerations for making sure the animations on our site are accessible, and that’s where the Web Content Accessibility Guidelines (WCAG) comes in.

While different contexts can affect the details of what you need to do, the WCAG provides a number of recommendations for animated content and interactions. These include guidelines for when to provide pause and play controls, limits for blinking or flashing the screen, and advice on when to provide reduced motion options for users with motion sensitivities. If you haven’t looked at it in a while, the specification has been updated to version 2.1, and now has even more useful guidance on how we can design web animations that are accessible. 

Let’s dig into each of those recommendations in more detail to see how we can apply them to our work on the web:

Pause, Stop, Hide 

The first of the WCAG recommendations that applies specifically to animation is Pause, Stop, Hide. For this one, the title gives a pretty big clue into what the recommendation is all about. It states:

For any moving, blinking or scrolling information that (1) starts automatically, (2) lasts more than five seconds, and (3) is presented in parallel with other content, there is a mechanism for the user to pause, stop, or hide it unless the movement, blinking, or scrolling is part of an activity where it is essential; […]

The recommendation specifically applies to motion initiated by the web page without user interaction, and it might sound like something that doesn’t apply to UI animation work at first. Most of the durations we might use in UI animation work are far under this five second threshold individually. But there are some common patterns where this would apply. For example: auto-advancing carousels or slideshows, animated backgrounds, or animated illustrations. While each individual animation within these patterns might still be very short, the overall motion that is created often plays out over more than five seconds. This is especially true when these are designed to play on an infinite loop, which is most definitely longer than five seconds.

How to meet the Pause, Stop, Hide criteria

If you have some of these longer playing animations, you’ll need to add some kind of pause and play controls that allow users to control the motion and/or auto playing behaviour. The WCAG specification doesn’t dictate what these controls need to look like though, you have complete design control over that.

A good example of this in practice is how the article series “Dark Side of The Grid” handles the example animations. Each animated figure loops infinitely once it starts, so they provide a play/stop button for readers to play the animation when they want to see it, and stop it when they’re done. Other more decorative or illustrative animations in the article play once and then present a button to replay them, if users want to. The placement and design of the buttons also fits the aesthetic of the overall design of the article which makes them both functional and aesthetically pleasing. 

Animated GIFs are something to look out for too. If you’ve got a looping animated GIF, that’s going to need some sort of pause/play controls to successfully meet this criteria. Both of the techniques mentioned in this post are helpful for pulling that off. 

There are some exceptions for this recommendation, as noted by the WCAG. One exception specifically worth noting is loaders and preloaders.

Three flashes or below threshold 

This recommendation is one that probably has the most research behind it because it stems from the days of broadcast TV. The main reason behind this recommendation is that significant flashing on screen has been known to trigger seizures.

In short three flashes or below threshold states: 

Web pages do not contain anything that flashes more than three times in any one second period, or the flash is below the general flash and red flash thresholds.

How to meet the three flashes or below threshold criteria

The WCAG provides details on the size, ratio and viewing angle thresholds under which flashing the screen could be considered safe. But for most of us, it’s probably easiest to avoid anything that flashes more than three times in one second. I don’t think many UX designers set out to flash the screen excessively on purpose, but it can happen. For example, a design that’s going for a video game sort of feel or a glitchy vibe might involve some screen flashing that happens more frequently than three times in a second. 

One specific example of a design that includes a significant amount of flashing is this article from the Huffington Post, pictured below. It’s a highly stylized piece on how millennials have a tougher go at things like jobs and saving for retirement than previous generations. Its  glitchy 8-bit video game design is very on point with the theme of the article. Design-wise, it’s a great choice for the subject matter and is well executed. But there are times, as you can see from the frame-by-frame stills below, where the text color flashes more than three times a second. 

This amount of flashing could be problematic for people with epilepsy or other physical reactions triggered by flashing. To their credit, the Huffington Post also provided a text-only version of the article for anyone sensitive to flashing, as Eileen mentions in this post, as well as advanced warning of the potential flashing hazard.

In general, avoiding effects that require frequent flashing is the safest way to meet this criteria. However, If you can’t avoid flashing animations in your project the WCAG provides detailed instructions around the safe thresholds for flashing the screen. Also, providing advanced warning of flashing content and an alternate version of the content without the flashing effect (like the example above) is a good thing to do as well.  

The A, AA, and AAA levels of the WCAG 

The WCAG has multiple levels of criteria and conformance, which is why each recommendation has a notation of what level it falls under. Level A compliance is the minimum level of conformance. Level AA is the middle level of conformance and indicates that the criteria for both level A and AA have been met. Level AAA is the highest level of conformance and requires satisfying the criteria from level A, AA and AAA. Typically, the guidelines found in level AAA require additional effort to meet. (If you want to learn more about these levels and what’s included in them outside of the animation-related recommendations we’re covering here, I’ve put together a list of helpful resources at the end of this article.) 

In general, most people are aiming for level AA compliance when they say they are making an accessible website. This is also the level you might see requested in an RFP or project brief. The last two guidelines we discussed fall under the level AA criteria and, therefore, must be met to claim level AA compliance. The next guideline, however, is part of the level AAA criteria. Even though it’s outside of the typical level of conformance, it’s a very useful recommendation to take into consideration if your project relies significantly on animation. I highly recommend implementing it in your work.

Animation from interactions 

This guideline covers a different kind of animation than the previous two. While the first two are generally applied to animation that’s initiated by the web page itself, this one applies to animation initiated by user interaction. More specifically, it states: 

Motion animation triggered by interaction can be disabled, unless the animation is essential to the functionality or the information being conveyed.

At first read, the term “motion animation” can be confusing since we typically use the terms “motion” and “animation” interchangeably. It might seem overly specific at first, but it makes sense to get this specific in this case. The WCAG defines motion animation as animation that is used to ”create the illusion of movement”, and specifies that “motion animation does not include changes of color, blurring or opacity.”

Essentially, the term motion animation is used to indicate that certain types of animation create the sense of movement, while others do not. It’s those animations that create a sense of movement that concerns this guideline. It’s important to keep that distinction in mind when discussing animation and accessibility to help make sure you focus your efforts efficiently. If we were to express this distinction in a very eyeball-like Venn Diagram, it would look  like this:

Over the last few years, we’ve come to realize that some types of motion on screen, even as part of an interface, can cause people with motion sensitivities to become physically ill. So this is why we might want to consider creating a reduced motion mode in our  work. I wrote more about the kinds of motion effects that are most likely to be triggering in this article, and this post from the WebKit blog covers some examples in detail.

How to meet the animation from interactions criteria

The WCAG suggests we avoid unnecessary animation, provide a control for users to turn off any non-essential motion, or take advantage of the reduced motion setting in operating systems and user agents. Let’s look at each of these in a bit more detail. There are a few different things we can do to help avoid exposing people to animation that might make them dizzy, nauseous, or worse.

Avoid unnecessary animation

Context and expectations also play a role here. The amount of motion you might reasonably expect to encounter on a website for a movie or video game is very different from what you might reasonably expect to encounter on say a government site or construction company’s site. The same amazing effects that might fit in just fine on a video game’s site would feel unnecessary or out of place on, say, a government website. Consider the context and expectations that apply to your site and whether the amount of animation you’re using in your design fits that context. 

Provide a way for users to turn off potentially problematic motion animation

If you have motion in your product that might be a trigger for folks with motion sensitivities, providing a way for users to avoid those triggering animations is the responsible thing to do. Based on the WCAG’s definition, any effect that could be considered motion animation should be one that includes a reduced version. 

Parallax effects are a good example. Those are universally problematic for folks with motion sensitivities based on my own research, yet it’s also still a very popular technique. While it wouldn’t be realistic to call for an end to all parallax effects entirely, implementing parallax responsibly requires giving your users some level of control to turn off that triggering motion. 

Typically, this is interpreted as including a toggle, setting, or preference for users to indicate their preference for reduced motion, and providing reduced versions of those motion animation effects when it’s activated. The Netlify 1 Million Devs site is one example of a motion toggle in action, and the official Animal Crossing site has one too.

Take advantage of the reduce motion feature 

Sites or apps that don’t rely heavily on large amounts of motion might find that a custom toggle isn’t the right strategy for them, and instead use the prefers-reduced-motion media query on its own. This allows you to provide a reduced version of highly animated content when that preference is present globally via the user’s operating system. It’s also a setting they can set in one place and have it affect a variety of content they encounter. That makes it a great tool for us to use to detect and respond to a user’s need for reduced motion. 

I’ve written about using prefers-reduced-motion in detail over at Smashing Magazine, and it’s also been covered by other articles on this site. In short, it allows us to access someone’s OS-level motion preference via a media query. We can access it in CSS or JavaScript and use the returned value to provide a reduced motion experience for those who want it. For example, we could do this to create a reduced motion variation of a bouncing CSS animation:  

/* A constant bouncing motion effect applied to the title */ h2 { animation: bouncing 1.5s linear infinite alternate; } /* Replace it with a safer effect when prefers-reduced-motion returns true */ @media (prefers-reduced-motion: reduce) { h2 { animation: fade 0.5s ease-in both; } } CodePen Embed Fallback

Some sites opt to use both a custom toggle and reduced motion preferences together. If you go to the site with reduced motion requested in your operating system settings, you automatically get the reduced motion mode. This two-pronged approach is a great strategy for sites with large amounts of motion. Marcy Sutton covers the basics of how to set up this approach in her egghead.io course, as well as in this CodePen demo

Use these guidelines for your next animation project

There you have it, everything the WCAG says about animation explained in one place. I hope this article will help you to confidently make your web animation work accessible. Sometimes it takes a little extra effort, but that extra effort is totally worth it when it means you’ve expanded the number of people who can meaningfully interact with your site.

This article focused on the recommendations specific to animation, but animation isn’t the only place in our work where accessibility considerations can make a big impact. There are some great resources on accessibility out there that cover a more holistic view on accessibility. One of my favorites is the book Accessibility for Everyone by Lara Kalbag. Sites like WebAIM and the A11y Project are great ones to check out for a wealth of resources. If you’re doing a lot of your animation work with SVG, Heather’s SVG accessibility article is a good resource as well. I highly recommend checking out these resources if you haven’t already. 

The post Accessible Web Animation: The WCAG on Animation Explained appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

ztext.js

Css Tricks - Tue, 09/22/2020 - 4:56am

Super cool project from Bennett Feely! It makes any web type into 3D lettering with a mouseover effect that moves the 3D objects in space. It’s reminiscent of Zdog, but for type. It works its magic by stacking a bunch of copies of the glyphs on top of each other that are offset by some translateZ, then using some perspective and rotateX/rotateY on a parent element to do the interactive stuff.

The effect is extremely fun. I can’t believe Fisher-Price hasn’t already implemented it site-wide.

Accessibility-wise, I have some questions. Even in the <h1> on the website, it turns into eight <h1> elements, which I can’t image is super great for screen readers, not to mention the slew of <span> elements inside. I’d think you could mitigate some of the problem with a single parent wrapper using an aria-label, yes?

Copy and paste also has weird results. If I copy, like, straight across a word, I tend to get just what I want. But if I copy from before the word to after it, I’ll get all the extra copies, which I definitely do not want. Maybe that’s fixable with some user-select: none; dancing.

It’s not just type, either! Bennet’s example on an <img> is neat in how it makes like printing a photo on (real world) canvas and stretching it around the frame so that even the edges have color.

My favorite is how it looks on <svg> though. So cool.

CodePen Embed Fallback

Direct Link to ArticlePermalink

The post ztext.js appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Thinking About Power Usage and Websites

Css Tricks - Mon, 09/21/2020 - 12:18pm

Gerry McGovern asked if I had any insight into energy consumption and websites. He has a book, after all, about the digital costs on the planet. He was wondering about the specifics of web tech, like…

If you do this in HTML it will consume 3× energy but if you do it in JavaScript it will consume 10×.

I would think if you really looked, and knew exactly how to measure it, you could find examples like that. Say I wanted to move an element across the screen. If I wrote a setInterval loop in JavaScript that incremented the left position on the relative-positioned element by one millisecond, I’m 99% sure that takes more literal electricity to do than if you were to do a CSS @keyframes animation over the same time where you changed the transform: translateX() value. In that example, usually, we’re thinking about performance moreso than energy consumption, but that’s interesting right away: does good performance map to lower energy usage? Probably.

Researches have looked into this.

We discover a statistically significant negative correlation between performance scores and the energy consumption of mobile web apps (with medium to large effect sizes), implying that an increase of the performance score tend to lead to a decrease of energy consumption.

They were testing mobile web apps on Android using Lighthouse scores. I can guess that maps pretty well to other platforms and other performance metrics.

I’m glad the research so far maps to what I would logically expect to be true. Things that lead to poor performance are things that take energy. Imagine images. You’ll be dinged on performance scores for serving too large or unoptimized images. Imagine the performance implications of that. There are two images sitting on a server, a large one and a small one. Which one takes more electricity to travel to some user’s computer? The large one. Which one takes more processing power to parse and display? The large one. Which one occupies more memory (which uses electricity) for the duration of it’s life on screen? The large one.

The less across the network, the less electricity.

The less your browser has to do, the less electricity.

Some ad that auto-refreshes itself every few seconds? Not only is it annoying, but it’s bandwidth-wasteful and thus wasteful with electricity. Whenever you have to resort to polling (i.e. making a network request over and over) rather than something event-based like web sockets? That’s using electricity that you may not have needed to use.

We know that CDNs are good for performance too. Rather than a file (like an image) needing to travel across the world, it comes from a server much geographically closer on a server designed for that job. This is where things get a little more murky to me.

With performance as our goal: objective achieved. With low-energy consumption as our goal, are we there?

It has been studied, but unfortunately, I can’t tell what the conclusion is from the abstract alone. In my mind, things are complicated by the fact that servers around the world are storing copies of these assets, and when the assets change, it’s not just one server where they update, but again, servers around the world. There has got to be a balance between the propagation and duplicative storage as far as the savings that would be realized by the efficiency of saving requests.

Speaking of storage efficiency, I’m certain that storage just sitting on disk takes a lot less electricity than files being sent over networks — but it still has a cost. Say you saved a copy of every file every time you changed it. Say you saved a complete copy of your website every time you deployed it. Useful? Sure. Does that cost electricity? It must. There must be some balance to strike there.

Gerry was asking me about particular technologies though. I can think of another big deal thing in CSS land: dark mode! Yet again, it’s been studied. Dark mode saves power.

Dark Mode can indeed reduce the display power draw by up to 58.5% at full brightness for the set of popular Android apps that we tested! In terms of whole phone battery drain reduction, that translates into 5.6% to 44.7% savings at full brightness and 1.8% to 23.5% savings at 38% brightness.

And what about comparing technologies? I suspect it’s far more about what that technology (or language) is doing than the language itself. For example, I can build a little area that opens and closes in HTML with a <details> element. Is that more energy-efficient than creating that area by attaching a click handler on a button that toggles the class of an element that visually opens and closes it? I kinda doubt it. I’d bet the electricity being used in the re-paint/re-render steps that the browser is doing and the languages behind it are less relevant. And yet! If I made the browser download a 50 KB JavaScript library just to implement my little open/close element, then yes, it does matter, and the JavaScript version is less efficient.

In that way, just as good performance generally maps to less energy consumption, I’d bet that adhering to the rule of least power generally maps to less energy consumption as well.

Sick of me guessing at stuff? Fair enough.

Jack Lenox’s article “How Improving Website Performance Can Help Save The Planet” on Smashing is a better deep dive. He points to websites that will test your site. Website Carbon Calculator is one example and it states:

Calculating the carbon emissions of website is somewhat of a challenge, but using five key pieces of data we can make a pretty good estimate:

1. Data transfer over the wire
2. Energy intensity of web data
3. Energy source used by the data centre
4. Carbon intensity of electricity
5. Website traffic

The testing code is open source.

The post Thinking About Power Usage and Websites appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Nova

Css Tricks - Mon, 09/21/2020 - 10:57am

Nova is a new (vehemently macOS-only) code editor from Panic, the folks behind Coda. It’s like “Coda 3” except this was such a major re-write that they gave it a whole new name.

I played with some of the betas as they were building it. I got a little discount as it went live, so I bought it and am using it here and there. Here’s my thought dump!

Like a lot of other people, I’m on the VS Code train. VS Code is very good and free. I work on a team where everyone else also uses VS Code. It’s going to be hard to dislodge my VS Code muscle memory. I’ve written about switching code editors before. The short story:

  1. Nothing can be obnoxious up front. As in, I can re-learn things after the transition.
  2. There has to be some killer feature that makes it appealing.

I really, really like Prettier and Emmet. If I couldn’t have those, I’d be out for sure. Fortunately, they are some of the top extensions.

I picked out a few I know I’ll want.

The default expansion for Emmet is Ctrl-E though, and it doesn’t work with Tab expansion (as far as I can tell), which isn’t my favorite. It does have all the extra fancy things Emmet can do though, which you can map to whatever keys you want.

The key binding setup is great. I was able to map all the things I’m used to, like setting Command-T to “Open Quickly” which is like the “Go to file…” setup in VS Code.

I have nearly 30 VS Code extensions activated. They all add some little nicety to VS Code for me specifically. I haven’t missed any of them yet. It would be a bonus to me if the default behavior of Nova was so good off the shelf that it didn’t need as many third-party tweaks (aside from the two biggies I already mentioned). For example, I don’t need a plugin to make my indendations all rainbow-ified because they already are!

But notice the JSX isn’t particularly well highlighted even though it’s on the right syntax.

“Find-in-project” is something I do at least a dozen times a day, so that’s something that needs to work tremendously well for me. My only issue so far is that it seems get stuck on “Indexing Files…” for me quite a bit (or feels stuck because it gets the ol’ fan spinning). That said, it seems to return good search results.

The Mac-ness of Nova is very, very strong. Scoping the “find-in-project” search results (say to only return *.js files) requires creating a new search scope. I can save that scope with a custom name which is a neat idea, but it has the very verbose UI-heavy search scoping from the MacOS Finder rather than a quick input field where I can quickly type *.js to scope results. In other words, it just feels like an example of emphasizing Mac-y-ness over usefulness.

Another mega Mac-y-ness thing is right-clicking a folder to open the file browser: it’s exactly like right-clicking a folder in the Finder. It’s comforting in a way, because that menu has a lot of powerful things in it.

But it also lacks things that might be contextually useful. For example, I miss an option to “Open this folder in a terminal window.”

The UI details are very nice. Selecting of coding font preferences is wonderful. The minimap looks great with little colored rectangles representing your code. The window and editor themes are very well done. Everything about the UI is just super classy.

It’s still a successor to Coda, so if you need to SFTP into remote servers and do direct editing, that’s there. I just had to do it the other day to edit a file I intentionally keep out of git, so that feature is still handy at times.

That’s a remote file system.

I otherwise would have used Coda for that, and didn’t even have to set it up for Nova because Panic Sync brought over all that auth info.

I do kind of dig that there is a built-in browser (Safari, of course). I’m wondering if I can get the muscle memory to be able to work within just this one application only without having to do much window-juggling. That means file browser, code editor, terminal, browser, and DevTools.

It’s a lot to see at once, but… kinda cool? I wish it had the option to use Chromium built-in as I happen to be more familiar with those DevTools There are some rough edges too, like my little tmux session in the terminal doesn’t respond to click events.

It’s interesting that Swift isn’t a built-in language. I would have guessed Panic even wrote at least parts of Nova in Swift given its Mac-y-ness.

If nothing else, you should check out the Nova landing page for all the CSS trickery! The animated clip-path on the image illustrating Nova’s themes is super cool (I heard clip-path animations are hardware accelerated in Safari, which is great!). It’s just some images stacked on top of each other all sharing the same animation, staggered out:

@keyframes wipe { 0% { clip-path: polygon(-50% 0%, 0% 0%, -50% 101%, -100% 101%) } 100% { clip-path: polygon(150% 0%, 200% 0%, 150% 101%, 100% 101%) } } /* ... */ img#interface1 { animation-delay: -17000ms; } img#interface2 { animation-delay: -15000ms; } img#interface3 { animation-delay: -13000ms; } img#interface4 { animation-delay: -11000ms; }

The <hr> though… that’s just gorgeous:

CodePen Embed Fallback

Oh, and check out the use of the display-p3 color format!

The post Nova appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Vue 3

Css Tricks - Fri, 09/18/2020 - 1:55pm

It’s out! Congrats to the Vue team for getting it done, I know it was a massive effort and a long time coming. All new docs, as well.

I like it’s still a priority that Vue can be used with just a <script> tag with no build process at all. But it’s ready for build processes too.

Vue 3.0 core can still be used via a simple <script> tag, but its internals has been re-written from the ground up into a collection of decoupled modules. The new architecture provides better maintainability, and allows end users to shave off up to half of the runtime size via tree-shaking.

If you specifically want to have a play with Vue Single File Components (SFCs, as they say, .vue files), we support them on CodePen in our purpose-built code editor for them. Go into Pen Settings > JavaScript and flip Vue 2 to Vue 3.

The train keeps moving too. This proposal to expose all component state to CSS is an awfully cool idea. I really like the idea of CSS having access to everything that is going on on a site. Stuff like global scroll and mouse position would be super cool. All the state happening on any given component? Heck yeah I’ll take it.

The post Vue 3 appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Enforcing performance budgets with webpack

Css Tricks - Fri, 09/18/2020 - 4:59am

As you probably know, a single monolithic JavaScript bundle — once a best practice — is no longer the way to go for modern web applications. Research has shown that larger bundles increase memory usage and CPU costs, especially on mid-range and low-end mobile devices.

webpack has a lot of features to help you achieve smaller bundles and control the loading priority of resources. The most compelling of them is code splitting, which provides a way to split your code into various bundles that can then be loaded on demand or in parallel. Another one is performance hints which indicates when emitted bundle sizes cross a specified threshold at build time so that you can make optimizations or remove unnecessary code.

The default behavior for production builds in webpack is to show a warning when an asset size or entry point is over 250KB (244KiB) in size, but you can configure how performance hints are shown and size thresholds through the performance object in your webpack.config.js file.

Production builds will emit a warning by default for assets over 250KB in size

We will walk through this feature and how to leverage it as a first line of defense against performance regressions.

First, we need to set a custom budget

The default size threshold for assets and entry points (where webpack looks to start building the bundle) may not always fit your requirements, but they can be configured to.

For example, my blog is pretty minimal and my budget size is a modest 50KB (48.8KiB) for both assets and entry points. Here’s the relevant setting in my webpack.config.js:

module.exports = {   performance: {     maxAssetSize: 50000,     maxEntrypointSize: 50000,   } };

The maxAssetSize and maxEntrypointSize properties control the threshold sizes for assets and entry points, respectively, and they are both set in bytes. The latter ensures that bundles created from the files listed in the entry object (usually JavaScript or Sass files) do not exceed the specified threshold while the former enforces the same restrictions on other assets emitted by webpack (e.g. images, fonts, etc.).

Let’s show an error if thresholds are exceeded

webpack’s default warning emits when budget thresholds are exceeded. It’s good enough for development environments but insufficient when building for production. We can trigger an error instead by adding the hints property to the performance object and setting it to 'error':

module.exports = {   performance: {     maxAssetSize: 50000,     maxEntrypointSize: 50000,     hints: 'error',   } }; An error is now displayed instead of a warning

There are other valid values for the hints property, including 'warning' and false, where false completely disables warnings, even when the specified limits are encroached. I wouldn’t recommend using false in production mode.

We can exclude certain assets from the budget

webpack enforces size thresholds for every type of asset that it emits. This isn’t always a good thing because an error will be thrown if any of the emitted assets go above the specified limit. For example, if we set webpack to process images, we’ll get an error if just one of them crosses the threshold.

webpack’s performance budgets and asset size limit errors also apply to images

The assetFilter property can be used to control the files used to calculate performance hints:

module.exports = {   performance: {     maxAssetSize: 50000,     maxEntrypointSize: 50000,     hints: 'error',     assetFilter: function(assetFilename) {       return !assetFilename.endsWith('.jpg');     },   } };

This tells webpack to exclude any file that ends with a .jpg extension when it runs the calculations for performance hints. It’s capable of more complex logic to meet all kinds of conditions for environments, file types, and other resources.

The build is now successful but you may need to look for a different way to control your image sizes. Limitations

While this has been a good working solution for me, a limitation that I’ve come across is that the same budget thresholds are applied to all assets and entry points. In other words, it isn’t yet possible to set multiple budgets as needed, such as different limits for JavaScript, CSS, and image files.

That said, there is an open pull request that should remove this limitation but it is not merged yet. Definitely something to keep an eye on.

Conclusion

It’s so useful to set a performance budget and enforcing one with webpack is something worth considering at the start of any project. It will draw attention to the size of your dependencies and encourage you to look for lighter alternatives where possible to avoid exceeding the budget.

That said, performance budgeting does not end here! Asset size is just one thing of many that affect performance, so there’s still more work to be done to ensure you are delivering an optimal experience. Running a Lighthouse test is a great first step to learn about other metrics you can use as well as suggestions for improvements.

Thanks for reading, and happy coding!

The post Enforcing performance budgets with webpack appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Optimizing CSS for faster page loads

Css Tricks - Thu, 09/17/2020 - 12:18pm

A straightforward post with some perf data from Tomas Pustelnik. It’s a good reminder that CSS is a crucial part of thinking web performance, and for a huge reason:

Any time [the browser] encounters any external resource (CSS, JS, images, etc.) it will assign it a download priority and initiate its download. Priorities are important because some resources are critical to render a page (eg. main stylesheet and JS files) while others may be less important (like images or stylesheets for other media types).

In the case of CSS, this priority is usually high because stylesheets are necessary to create CSSOM (CSS Object Model). To render a webpage browser has to construct both DOM and CSSOM.

That’s why CSS is often referred to as a “blocking” resource. That’s desirable to some degree: we wouldn’t want to see flash-of-unstyled-websites. But we get real perf gains when we make CSS smaller because it’s quicker to download, parse, and apply.

Aside from the techniques in the post, I’m sure advocates of atomic/all-utility CSS would love it pointed out that the stylesheets from those approaches are generally way smaller, and thus more performant. CSS-in-JS approaches will sometimes bundle styles into scripts so, to be fair, you get a little perf gain at the top by not loading the CSS there, but a perf loss from increasing the JavaScript bundle size in the process. (I haven’t seen a study with a fair comparison though, so I don’t know if it’s a wash or what.)

Direct Link to ArticlePermalink

The post Optimizing CSS for faster page loads appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Weaved Webs

Css Tricks - Wed, 09/16/2020 - 12:16pm

There is a bit of an irony with Jamstack.

The concept is simple: you put pre-rendered, static files on web hosting (a CDN) designed to do that well. That’s it. If you need to do more, anything you do from there is done with client-side JavaScript, which is likely talking to serverless functions because that’s the spiritual partner to Jamstack on the back end. I heard Guillermo Rauch say at Smashing Conf the other day that it isn’t exactly a “stack” in that it’s almost entirely non-prescriptive in what you do. While I like the word Jamstack, that also feels fair.

The irony is that while the concept is simple, that simplicity can be the cause of complexity.

Netlify, the company largely behind Jamstack, knows this. They know that without a back-end server with back-end languages, something like a basic contact form gets complicated. Instead of being in no-brainer solved-problem territory, we have to figure out another way to process that form. So, they solve that problem for you (among others, like auth and serverless functions). But there are tons of other companies that want to be that cog in your machine.

That’s just one potential complication. What do you use for a CMS or other data storage? What is your build process like? How do you see previews of content changes? How do you do auth? What if you need some fancy calendar widget? What if you want to sell something? Anything a website can do, Jamstack has an answer for — it’s just that combining all those answers can feel disjointed and potentially confusing.

Dave recently played with Eleventy + Tailwind + Netlify CMS (which is Jamstack-y) and said it felt like cattle herding:

So my little mashup, which was supposed to be just 3 technologies ended up exposing me to ~20 different technologies and had me digging into nth-level dependency source code after midnight. If there’s an allegory for what I don’t like about modern-day web development, this is it. You want to use three tools, but you have to know how to use twenty tools instead. If modules and components are like LEGO, then this is dumping out the entire bin on the floor just to find one tiny piece you need.

“The tangled webs we weave,” indeed.

In a conversation between Richard MacManus and Matt Mullenweg¹, Richard quotes Matt:

You can patch together a dozen services, each with its own account and billing, for hundreds of dollars a month, to get a similar result you’d have for a few dollars a month using WordPress on shared hosting,” he said. “And it would be more fragile, because the chain is only as strong as its weakest link. You are chaining together different toolsets, logins, billing, hosting… any part of it going down can break the entire flow.

If I was considering Jamstack for a particular project, and the grand total really was twelve services, I probably would reconsider, particularly if I could reach for a tool like WordPress and bring it down to one. There are plenty of other fair criticisms of Jamstack, particularly since it is early-days. The story of “CMS with Preview” isn’t particularly great, for example, which is a feature you don’t even think about with WordPress because, duh, obviously it has that.

And Jamstack can do some things that are very ahead of the game that I cherish. Git-based deployment? All websites should have that. Previews of my pull requests? Hot damn. Sub -100-millisecond first requests? Yes please. Not having to diddle with cache? Sweet. Catch up, other stacks.

I’m saying there are baby bear choices to be made here. You get there by doing what you’re probably already doing anyway: putting your adult pants on, thinking about what your project needs, and choosing the best option.

I have production WordPress sites. Like this one! It’s great!

I have production Jamstack sites. Like this one! It’s not a complicated web of services. It’s a static site generator with content in the GitHub repo deployed with Netlify. While CSS-Tricks can do about 100 things that this site can’t, it has a few tricks up its sleeve that CSS-Tricks can’t do, like accept pull requests on content.

I feel like I’ve chosen pretty well in all my cases.

  1. While Matt is clearly incentivized to defend the WordPress approach, it feels to me the opinions here are genuine; in part because Automattic invests in alternative stack approaches, and that WordPress and Jamstack are not mutually exclusive. I enjoyed responses to this, like Ohad Eder-Pressman’s open letter, which is also full of incentivized-but-genuine thoughts.

The post Weaved Webs appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Lessons Learned from Sixty Days of Re-Animating Zombies with Hand-Coded CSS

Css Tricks - Wed, 09/16/2020 - 4:56am

Caution: Terrible sense of humor ahead. We’ll talk about practical stuff, but the examples pretty much all involve zombies and silly jokes. You have been warned.

I’ll be linking to individual Pens as I discuss the lessons I learned, but if you’d like to get a sense of the entire project, check out 60 days of Animation on Undead Institute. I started this project to end on August 1st, 2020, coinciding with the publication of a book I wrote featuring CSS animation, humor, and zombies — because, obviously, zombies will destroy the world if you don’t brandish your web skills and stop the apocalypse. Nothing puts the hurt on the horde like a HTML element on the move!

I had a few rules for myself throughout the project. 

  1. I would hand-code all CSS. (I’m a masochist.)
  2. The user would initiate all of the animation. (I hate coming upon an animation that’s already halfway through.) 
  3. I would use JavaScript as little as possible and never for animation. (I only ended up using JavaScript once, and that was to start audio with the final animation. I have nothing against JavaScript, it’s just not what I wanted to do here.)
Lesson 1: Eighty days is a long time.

Uh, doesn’t the title say “sixty” days? Yes, but my original goal was to do eighty days and as day one approached with less than twenty animations prepared and a three day average for each production, I freaked out and switched to sixty days. That gave me both twenty more days till the beginning date and twenty fewer pieces to do.

Lesson 1A: Sixty days is still a long time.

That’s a lot of animation to do with a limited amount of time, ideas, and even more limited artistic skills. And while I thought of dropping to thirty days, I’m glad I didn’t. Sixty days stretched me and forced me to go deeper into how CSS animation — and by extension, CSS itself — works. I’m also proudest of many of the later pieces I did as my skills increased, and I had to be more innovative and think harder about how to make things interesting. Once you’ve used all the easy options, the actual work and best results begin. (And yes, it ended up being sixty-two days because I started on June 1 and wanted to do a final animation on August 1. Starting June 3 just felt icky and wrong.)

So, the real Lesson 1: stretch yourself.

Lesson 2: Interactive animations are hard, and even harder to make responsive. 

If you want something to fly across the screen and connect with another element or appear to start another element’s move, you must use either all standard, inflexible units or all flexible units. 

Three variables determine when and where an animated element will be during any animation: duration, velocity, and distance. The duration of the animation is set in the animation property and cannot be changed in relation to screen size. The animation timing function determines the velocity; screen size can’t change that either. Thus, if the distance varies with the screen size, the timing will be off everywhere except a specific screen width and height. 

Look at Tank!. Run the animation at wide and narrow screen sizes. While I got the timing close, if you compare the two, you’ll see that the tank is in a different place relative to the zombies when the last zombies fall.

To avoid these timing issues, you can use fixed units and a large number, like 2000 or 5000 pixels or more, so that the animation will cover the width (or height) of the screen for all but the largest monitors.  

Lesson 3: If you want a responsive animation, put everything in (one of the) viewport units. 

Going halfsies on unit proportions (e.g. setting width and height in pixels, but location and movement with viewport units) will lead to unpredictable results. Don’t use both vw and vh either but one or the other; whichever will be the dominant orientation. Mixing vh and vw units will make your animation go “wonky” which I believe is the technical term. 

Take Superbly Zomborrific, for instance. It mixes pixel, vw, and vh units. The premise is that the Super Zombie is flying upward as the “camera” follows. Super Zombie smashes into a ledge and falls as the camera continues, but you wouldn’t understand that if your screen was sufficiently tall.

That also means that if you need something to come in from the top — like I did in Nobody Here But Us Humans —you must set the vw height high enough to ensure that the ninja zombie isn’t visible at most aspect ratios.

Lesson 3A: Use pixel units for movements within an SVG element. 

All that said, transforming elements within an SVG element should not use viewport units. SVG tags are their own proportional universe. The SVG “pixel” will stay proportional within the SVG element to all the other SVG element children while viewport units will not. So transform with pixel units within an SVG element, but use viewport units everywhere else.

Lesson 4: SVGs scale horribly at runtime.

For animations, like Oops…, I made the SVG image of the zombie scale up to five times his size, but that makes the edges fuzzy. [Shakes fist at “scalable” vector graphics.]

/* Original code resulting in fuzzy edges */ .zombie {   transform: scale(1);   width: 15vw; } .toggle-checkbox:checked ~ .zombie {   animation: 5s ease-in-out 0s reverseshrinkydink forwards; } @keyframes reverseshrinkydink {   0% {     transform: scale(1);   }   100% {     transform: scale(5);   } }

I learned to set their dimensions to the final dimensions that would be in effect at the end of the animation, then use a scale transform to shrink them down to the size for the start of the animation. 

/* Revised code */ .zombie {   transform: scale(0.2);   width: 75vw; } .toggle-checkbox:checked ~ .zombie {   animation: 5s ease-in-out 0s reverseshrinkydink forwards; } @keyframes reverseshrinkydink {   0% {     transform: scale(0.2);   }   100% {     transform: scale(1);   } }

In short, the revised code moves from a scaled-down version of the image up to the full width and height. The browser always renders at 1, making the edges crisp and clean at a scale of 1. So instead of scaling from 1 to 5, I scaled from 0.2 to 1.

Lesson 5: The axis Isn’t a universal truth. 

An element’s axes stay in sync with the element, not the page. A 90-degree rotation before a translateX will change the direction of the translateX from horizontal to vertical. In Nobody Here But Us Humans… 2, I flipped the zombies using a 180-degree rotation. But positive Y values move the ninjas towards the top, and negative ones move them towards the bottom (the opposite of normal). Beware of how a rotation may affect transforms further down the line.

Lesson 6. Separate complex animations into concentric elements to make easier adjustments.

When creating a complex animation that moves in multiple directions, adding wrapper divs, or rather parent elements, and animating each one individually will cut down on conflicting transforms, and prevent you from becoming a weepy mess.

For instance, in Space Cadet, I had three different transforms going on. The first is the zomb-o-naut’s moving in an up and down motion. The second is a movement across the screen. The third is a rotation. Rather than trying to do everything in a single transform, I added two wrapping elements and did one animation on each element (I also saved my hair… at least some of it.) This helped avoid the axis issues discussed in the last lesson because I performed the rotation on the innermost element, leaving its parent’s and grandparent’s axes in place.

Lesson 7: SVG and CSS transforms are the same. 

Some paths and groups and other SVG elements will already have transforms defined on them. It could be from an optimization algorithm, or perhaps it’s just how the illustration software generates the code. If a path, group, or whatever element in an SVG already has an SVG transform on it, removing that transform will reset the element, often to a bizarre location or size compared to the rest of the drawing. 

Since SVG and CSS transforms are the same, any CSS transform you do replaces the SVG transform, meaning your CSS transform will start from that bizarre location or size rather than the location or size that is set in the the SVG.

You can copy the transform from the SVG element to your CSS and set it as the starting position in CSS (updating it to the CSS syntax first, of course). You can then modify it in your CSS animation.

For instance, in Uhhh, Yeah…, my tribute to Office Space, Undead Lumbergh’s right upper arm (the #arm2 element) had a transform on it in the original SVG code.

<path id="arm2" fill="#91c1a3" fill-rule="nonzero" d="M0 171h9v9H0z" transform="translate(0 -343) scale(4 3.55)"/>

Moving that transform to CSS like this:

<path id="arm2" fill="#91c1a3" fill-rule="nonzero" d="M0 171h9v9H0z"/> #arm2 {   transform: translate(0, -343px) scale(4, 3.55); }

…I could then create an animation that doesn’t accidentally reset the location and scale:

.toggle-checkbox:checked ~ .z #arm2 {    animation: 6s ease-in-out 0.15s arm2move forwards; } @keyframes arm2move {   0%, 100% {     transform: translate(0, -343px) scale(4, 3.55);   }   40%, 60% {     transform: translate(0, -403px) scale(4, 3.55);   }   50% {     transform: translate(0, -408px) scale(4, 3.55);   } } 

This process is harder when the tool generating the SVG code attempts to “simplify” the transform into a matrix. While you can recreate the matrix transform by copying it into the CSS, it is a difficult task to do. You’re a better developer than me — which might be true anyway — if you can take a matrix transform and manipulate it to scale, rotate, or translate in the exact way you want.

Alternatively, you can recreate the matrix transform using translation, rotation, and scaling, but if the path is complex, the likelihood that you can recreate it in a timely manner without finding yourself in a straight jacket is low. 

The last and probably easiest option is to wrap the element in a group (<g>) tag. Add a class or ID to it for easy CSS access and transform the group itself, thus separating out the transforms as discussed in the last lesson. 

Lesson 8: Keep your sanity by using transform-origin when transforming part of an SVG

The CSS transform-origin property moves the point around which the transform happens. If you’re trying to rotate an arm — like I did in Clubbin’ It —  your animation will look more natural if you rotate the arm from the center of the shoulder, but that path’s natural transform origin is in the upper-left. Use transform-origin to fix this for smoother, more natural feel… you know that really natural pixel art look…

Transforming the origin can also be useful when scaling, like I did in Mustachioed Oops, or when rotating mouth movements, such as the dinosaur’s jaw in Super Tasty. If you don’t change the origin, the transforms will use an origin point at the upper left corner of the SVG element. 

Lesson 9: Sprite animations can be responsive

I ended up doing a lot of sprite animations for this project (i.e., where you use multiple, incremental frames and switch between them fast enough that the characters seem to move). I created the images in one wide file, added them as a background image to an element the size of a single frame, used background-size to set the background image to the width of the image, and hid the overflow. Then I used background-position and the animation timing function, step(), to walk through the images; for example: Post-Apocalyptic Celebrations.

Before the project, I always used inflexible images. I’d scale things down a little so that there would be at least a little responsive give, but I didn’t think you could make it a fully flexible width. However, if you use SVG as the background image you can then use viewport units to scale the element along with the changing screen size. The only problem is the background position. However, if you use viewport units for that, it will stay in sync. Check that out in Finally, Alone with my Sandwich…

CodePen Embed Fallback Lesson 9A: Use viewport units to set the background size of an image when creating responsive sprite animation

As I’ve learned throughout this project, using a single type of unit  is almost always the way to go. Initially, I’d set my sprite’s background size using percentages. The math was easy (100% * (number of steps + 1)) and it worked fine in most cases. In longer animations, however, the exact frame tracking could be off and parts of the wrong sprite frame might display. The problem grows as more frames are added to the sprite. 

I’m not sure the exact reason this causes an issue, but I believe it’s because of rounding errors that compound over the length of the sprite sheet (the amount of the shift increases with the number of frames). 

For my final animation, It Ain’t Over Till the Zombie Sings, I had a dinosaur open his mouth to reveal a zombie Viking singing (while lasers fired in the background plus there was dancing, accordions playing and zombies fired from cannons, of course). Yeah, I know how to throw a party… a nerd party.

The dinosaur and viking was one of the longest sprite animations I did for the project. But when I used percentages to set the background size, the tracking would be off at certain sizes in Safari. By the end of the animation, part of the dinosaur’s nose from a different frame would appear to the right and a similar part of the nose would be missing on the left.

The dinosaur on the left is missing part of his left cheek and growing a new one next to his right cheek.

This was super frustrating to diagnose because it seemed to work fine in Chrome and I’d think I fixed it in Safari only to look at a slightly different screen size and see the frame off again. However, if I used consistent units — i.e. vw for background-size, frame width, and background-position — everything worked fine. Again, it comes down to working with consistent units!

Lesson 10: Invite people into the project.

While I learned tons of things during this process, I beat my head against the wall for most of it (often until the wall broke or my head did… I can’t tell). While that’s one way to do it, even if you’re hard-headed, you’ll still end up with a headache. Invite others into your project, be it for advice, to point out an obvious blind spot you missed, provide feedback, help with the project, or simply to encourage you to keep going when the scope is stupidly and arbitrarily large. 

So let me put this lesson into practice. What are your thoughts? How will you stop the zombie hordes with CSS animation? What stupidly and arbitrarily large project will you take on to stretch yourself?

The post Lessons Learned from Sixty Days of Re-Animating Zombies with Hand-Coded CSS appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Inclusive Design 24

Css Tricks - Wed, 09/16/2020 - 4:55am

Totally free.

No sign-up. No registration. All sessions are streamed live and publicly on the Inclusive Design 24 YouTube channel – see the entire playlist for the event.

Quite the lineup.

I’ve got a couple of other accessibility links burning a hole in my pocket as well:

Direct Link to ArticlePermalink

The post Inclusive Design 24 appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Syndicate content
©2003 - Present Akamai Design & Development.