Author: techgirl

Creating Reusable Base Classes in TypeScript with a Real-Life Example

Hey CSS-Tricksters! Bryan Hughes was kind enough to take a concept from an existing post he published on converting to TypeScript and take it a few couple steps further in this post to elaborate on creating reusable base classes. While this post doesn’t require reading the other one, it’s certainly worth checking it out because it covers the difficult task of rewriting a codebase and writing unit tests to help the process.

Johnny-Five is an IoT and robotics library for Node.js. Johnny-Five makes it easy to interact with hardware by taking a similar approach that jQuery took to the web a decade ago: it normalizes the differences between various hardware platforms. Also like jQuery, Johnny-Five provides higher-level abstractions that make it easier to work with the platform.

Johnny-Five supports a wide array of platforms via IO Plugins, from the Arduino family, to the Tessel, to the Raspberry Pi, and many more. Each IO Plugin implements a standardized interface for interacting with lower-level hardware peripherals. Raspi IO, which I first created five years ago, is the IO plugin that implements support for the Raspberry Pi.

Any time there are multiple implementations that conform to one thing, there is a chance to share code. IO Plugins are no exception, however, we have not shared any code between IO Plugins to date. We recently decided, as a group, that we wanted to change this. The timing was fortuitous since I was planning on rewriting Raspi IO in TypeScript anyways, so I agreed to take on this task.

The goals of a base class

For those who many not be familiar with using class-based inheritance to enable code sharing, let’s do a quick walk-through of what I mean when I say “creating a base class to reuse code.”

A base class provides structure and common code that other classes can extend. Let’s take a look at a simplified TypeScript example base class that we will extend later:

abstract class Automobile {   private _speed: number = 0;   private _direction: number = 0;   public drive(speed: number): void {     this._speed = speed;   }      public turn(direction: number): void {     if (direction > 90 || direction < -90) {       throw new Error(`Invalid direction "$  {direction}"`);     }     this._direction = direction;   }      public abstract getNumDoors(): number; }

Here, we have created a base class that we call Automobile. This provides some basic functionality shared between all types of automobiles, whether it’s a car, a pickup, etc. Notice how this class is marked as abstract, and how there is one abstract method called getNumDoors. This method is dependent on the specific type of automobile. By defining it as an abstract class, we are saying that we require another class to extend this class and implement this method. We can do so with this code:

class Sedan extends Automobile {   public getNumDoors(): number {     return 4;   } }  const myCar = new Sedan(); myCar.getNumDoors(); // prints 4 myCar.drive(35);     // sets _speed to 35 myCar.turn(20);      // sets _direction to 20

We’re extending the Automobile class to create a four-door sedan class. We can now call all methods on both classes, as if it were a single class.

For this project, we’ll create a base class called AbstractIO that any IO plugin author can then extend to implement a platform-specific IO Plugin.

Creating the Abstract IO base class

Abstract IO is the base class I created to implement the IO Plugin spec for use by all IO Plugin authors, and is available today on npm.

Each author has their own unique style, some preferring TypeScript and others preferring vanilla JavaScript. This means that, first and foremost, this base class must conform to the intersection of TypeScript best practices and JavaScript best practices. Finding the intersection of best practices isn’t always obvious though. To illustrate, let’s consider two parts of the IO Plugin spec: the MODES property and the digitalWrite method, both of which are required in IO Plugins.

The MODES property is an object, with each key having a human readable name for a given mode type, such as INPUT, and the value being the numerical constant associated with the mode type, such as 0. These numerical values show up in other places in the API, such as the pinMode method. In TypeScript, we would want to use an enum to represent these values, but JavaScript doesn’t support it. In JavaScript, the best practice is to define a series of constants and put them into an object “container.”

How do we resolve this apparent split between best practices? Create one using the other! We start by defining an enum in TypeScript and define each mode with an explicit initializer for each value:

export enum Mode {  INPUT = 0,  OUTPUT = 1,  ANALOG = 2,  PWM = 3,  SERVO = 4,  STEPPER = 5,  UNKNOWN = 99 }

Each value is carefully chosen to map explicitly to the MODES property as defined by the spec, which is implemented as part of the Abstract IO class with the following code:

public get MODES() {  return {    INPUT: Mode.INPUT,    OUTPUT: Mode.OUTPUT,    ANALOG: Mode.ANALOG,    PWM: Mode.PWM,    SERVO: Mode.SERVO,    UNKNOWN: Mode.UNKNOWN  } }

With this, we have nice enums when we’re in TypeScript-land and can ignore the numerical values entirely. When we’re in pure JavaScript-land, we still have the MODES property we can pass around in typical JavaScript fashion so we don’t have to use numerical values directly.

But what about methods in the base class that derived classes must override? In the TypeScript world, we would use an abstract class, as we did in the example above. Cool! But what about the JavaScript side? Abstract methods are compiled out and don’t even exist in the output JavaScript, so we have nothing to ensure methods are overridden there. Another contradiction!

Unfortunately, I couldn’t come up with a way to respect both languages, so I defaulted to using the JavaScript approach: create a method in the base class that throws an exception:

public digitalWrite(pin: string | number, value: number): void {  throw new Error(`digitalWrite is not supported by $  {this.name}`); }

It’s not ideal because the TypeScript compiler doesn’t warn us if we don’t override the abstract base method. However, it does work in TypeScript (we still get the exception at runtime), as well as being a best practice for JavaScript.

Lessons learned

While working through the best way to design for both TypeScript and vanilla JavaScript, I determined that the best way to solve discrepancies is:

  1. Use a common best practice shared by each language
  2. If that doesn’t work, try to use the TypeScript best practice “internally” and map it to a separate vanilla JavaScript best practice “externally,” like we did for the MODES property.
  3. And if that approach doesn’t work, default to using the vanilla JavaScript best practice, like we did for the digitalWrite method, and ignore the TypeScript best practice.
  4. These steps worked well for creating Abstract IO, but these are simply what I discovered. If you have any better ideas I’d love to hear them in the comments!

    I discovered that abstract classes are not useful in vanilla JavaScript projects since JavaScript doesn’t have such a concept. This means that they are an anti-pattern here, even though abstract classes are a TypeScript best practice. TypeScript also doesn’t provide mechanisms to ensure type-safety when overriding methods, such as the override keyword in C#. The lesson here is that you should pretend that abstract classes don’t exist when targeting vanilla JavaScript users as well.

    I also learned that it’s really important to have a single source of truth for interfaces shared across modules. TypeScript uses duck typing as its core type system pattern, and is very useful inside any given TypeScript project. However, synchronizing types across separate modules using duck typing turned out to be more of a maintenance headache than exporting an interface from one module and importing it into another. I had to keep publishing little changes to modules until I got them aligned on their types, leading to excess version number churn.

    The final lesson I learned isn’t a new one: get feedback throughout the design process from library consumers. Knowing this going in, I set up two primary rounds of feedback. The first round was in person at the Johnny-Five collaborator’s summit where we brainstormed as a group. The second round was a pull request I opened against myself, despite being the only collaborator on Abstract IO with permission to merge pull requests. The pull request proved invaluable as we sifted through the details as a group. The code at the beginning of the PR bared little resemblance to the code when it was merged, which is good!

    Wrapping up

    Producing base classes destined to be consumed by both TypeScript and vanilla JavaScript users is a mostly straightforward process, but there are some gotchas. Since TypeScript is a superset of JavaScript, the two mostly share the same best practices. When differences in best practices do arise, a little creativity is required to find the best compromise.

    I managed to achieve my goals with Abstract IO, and implemented a base class that serves both TypeScript and vanilla JavaScript IO Plugin authors well. Turns out, it’s (mostly) possible to have your cake and eat it too!

    The post Creating Reusable Base Classes in TypeScript with a Real-Life Example appeared first on CSS-Tricks.

    CSS-Tricks

, , , , , ,

Faking env() to Use it Now

There is already an env() function in CSS, but it kinda came out of nowhere as an Apple thing for dealing with “The Notch” but it has made it’s way to be a draft spec. The point will be for UAs or authors to declare variables that cannot be changed. Global const for CSS, sorta.

That spec doesn’t seem to suggest how we’ll actually set those env() values just yet. If you want them now, the easiest way to fake them would be using regular ol’ CSS custom properties and simply not change them.

But if you want that env() syntax though, there is a PostCSS plugin for emulating it. The way the plugin handles them is through a JavaScript file that declares them.

postcssCustomProperties({   importFrom: 'path/to/file.js' /* module.exports = {     environmentVariables: {       '--branding-padding': '20px',       '--branding-small': '600px'     }   } */ });

Having them start life as JavaScript is interesting, as it means we could perhaps have a single place to set variables that are accessible both to JavaScript and CSS.

That’s what Harry Nicholls covers more in his article, “Why you should use CSS env()” like some gotchas when dealing with units and such. But if you really needed a single source for unchangeable variables in both CSS and JavaScript, then I’d say this is a good way to go — and could potentially be ripped out once support for env() formally arrives.

The post Faking env() to Use it Now appeared first on CSS-Tricks.

CSS-Tricks

[Top]

Clever code

This week, Chris Ferdinandi examined a clever JavaScript snippet, one that’s written creatively with new syntax features, but is perhaps less readable and performant. It’s a quick read, but his callout of our industry’s fixation on cleverness is worth… calling out:

…we’ve become obsessed as an industry with brevity and clever code, and it results in code that’s sometimes less performant, and typically harder to read and make sense of for most people.

He made a similar argument late last month when he wrote about code readability, noting that brevity might look cool but ultimately leads to all sorts of issues in a codebase:

Often, web developers are obsessed with brevity. There’s this thing were developers will try to write the same function in the fewest number of characters possible.

Personally, I think brevity is pointless. Readability is a lot more important.

I entirely agree with Chris on this point, however, I think there is one important distinction to make and that’s the difference between code that’s intended as a prototype and code that’s intended for production. As Jeremy Keith argued a short while ago:

What’s interesting is that—when it comes to prototyping—our usual front-end priorities can and should go out the window. The priority now is speed. If that means sacrificing semantics or performance, then so be it. If I’m building a prototype and I find myself thinking “now, what’s the right class name for this component?”, then I know I’m in the wrong mindset. That question might be valid for production code, but it’s a waste of time for prototypes.

I agree with Chris that we should be writing code that is easy to read when we’re in production. I also think experimenting with code in this way is a good thing when it comes to prototypes. We shouldn’t ever shy away from playing with code and pushing things a little bit – so long as we’re not doing that in a giant web app with a a team of other developers working alongside us.


I’ve noticed that there are some folks that are doing genuinely ingenious things with Sass. I consistently sit back and think, “Wow, I’ve never seen anything like this before.” But when it comes to a production web app that has to be understood by hundreds of people at the same time, I don’t believe that this is the reaction we want when someone looks at the code.

As a result, I’ve been trying to write Sass code that is actually so simple that it almost looks dumb. One easy way to make code a lot simpler is to reduce the amount of nesting:

.element {   .heading { ... } }

This looks fine when there’s code inside — and it’s pretty easy to understand — but add a complex bit of design in the mix (say, using pseudo elements and media queries) and you suddenly have a rather complex set of rules in front of you. Creativity and cleverness can be harder to scan and identify one small part of the code that you’re looking for. Plus, in this example, we’ve unnecessarily made our .heading class a little bit more specific which might encourage us to override things in a hacky way elsewhere in the codebase.

We could write the following:

.element { ... }  .element-heading { ... }

I know this looks foolishly simple but the relationship between these two classes is easier to see and easier to extend in the future. Bundling all that code into a single nested class can get out of hand real fast. Even if it happens to look a lot cooler.

(As an aside, Andy Bell’s post on using the ampersand in Sass — and the resulting comments — is a great example of the clash between creativity and practicality.)

Anyway, the point I’m trying to make here is that CSS (and JavaScript for that matter) is a strange language because there are no definite rules you can make about it. It all really depends on the codebase and the project. But I think we can safely say that our code ought to be a lot more boring than our prototypes when it moves to production.

Continue to make prototypes that are wild and experimental or impossibly weird! Code quality be damned.

The post Clever code appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]

One or More of These 10 Top WordPress Plugins Can Take Your Site to The Next Level

[Top]

Claim Your .design Domain Name, Before It’s Gone!

[Top]

The Power of Named Transitions in Vue

Vue offers several ways to control how an element or component visually appears when inserted into the DOM. Examples can be fading in, sliding in, or other visual effects. Almost all of this functionality is based around a single component: the transition component.

A simple example of this is with a single v-if based on a Boolean. When the Boolean is true, the element appears. When the Boolean is false, the element disappears. Normally, this element would just pop in and out of existence, but with the transition component you can control the visual effect.

<transition>   <div v-if="isVisible">is this visible?</div> </transition>

Several articles have been written that cover the transition component quite well, like articles from Sarah Drasner, Nicolas Udy, and Hassan Djirdeh. Each article covers different aspects of Vue’s transition component in detail. This article will expand on the topic by focusing on one aspect of the transition component; the fact that they can be “named.”

<transition name="fade">   <div v-if="isVisible">is this visible?</div> </transition>

The initial change this attribute offers is that the CSS classes injected onto the element during the transition sequence will be prefixed by the given name. Basically, it would be fade-enter instead of v-enter from the example above. This single attribute can go well beyond this simple option. It can be used to leverage certain features of Vue and CSS which allows for some interesting outcomes.

Another thing to consider is that the name attribute can be bound:

<transition v-bind:name="currentTransition">   <div v-if="isVisible">is this visible?</div> </transition>

In this example, the transition will be named the value currentTransition resolves to. This simple change provides another level of options and features to an app’s animations. With static and dynamic named transitions, a project can have a series of prebuilt transitions ready to apply throughout the entire app, components that can extend existing transitions applied to them, switch a transition being used before or after being applied, allowing users to choose transitions, and control how individual elements of a list transition into place based on the current state of that list.

This article is intended to explore these features and explain how to use them.

What happens when transitions are named?

By default, when a transition component is used, it applies specific classes in a specific sequence to the element. These classes can be leveraged in CSS. Without any CSS, these classes, in essence, do nothing for the element. Therefore, there is a need for CSS of this nature:

.v-enter, .v-leave-to {   opacity: 0; }  .v-enter-active, .v-leave-active {   transition: 0.5s; }

This causes the element to fade in and out with a duration of half a second. A minor change to the transition provides for elegant visual feedback to the user. Still, there is an issue to consider. But first, what’s different with a named transition?

.fade-enter, .fade-leave-to {   opacity: 0; }  .fade-enter-active, .fade-leave-active {   transition: 0.5s; }

Essentially the same CSS but with fade- prefixed instead of v-. This naming addresses the potential issue that can happen when using the default class names of the transition component. The v- prefix makes the classes global in effect, especially if the CSS is placed in the style block of the app’s root level. This would, in effect, make *all* transitions without a name attribute throughout the entire app use the same transition effect. For small apps this may suffice, but in larger, more complex apps, it may lead to undesirable visual effects, as not everything should fade in and out over half a second.

Naming transitions provides a level of control for developers throughout the project as to how different elements or components are inserted or removed visually. It is suggested that all transitions be named — even if there is just one — to establish the habit of doing so. Even if an app has only one transition effect, there may be a need to add a new one at a future point. Having already named existing transitions in the project eases the effort of adding a new one.

Building a collection of transition effects

Naming transitions provides for a simple yet very useful process. A common practice might be to create the transition classes as part of the component that is using them. If another common practice of scoping styles for a component is done, those classes will only be available to that particular component. If two different components have similar transitions in their style blocks, then we are just duplicating code.

So, let’s consider keeping CSS for transitions in the style block of the root of the app, typically the app.vue file. For most of my projects, I place them as the last section of the style block, making them easy to locate for adjustments and additions. Keeping the CSS in this location makes the transition effects available to every use of the transition component throughout the entire app. Here are examples from some of my projects.

.fade-enter, .fade-leave-to { opacity: 0; } .fade-enter-active, .fade-leave-active { transition: 0.5s; }  .slide-enter {   opacity: 0;   transform: scale3d(2, 0.5, 1) translate3d(400px, 0, 0); }  .slide-enter-to { transform: scale3d(1, 1, 1); } .slide-enter-active, .slide-leave-active { transition: 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55); } .slide-leave { transform: scale3d(1, 1, 1); }  .slide-leave-to {   opacity: 0;   transform: scale3d(2, 0.5, 1) translate3d(-400px, 0, 0); }  .rotate-enter { transform: perspective(500px) rotate3d(0, 1, 0, 90deg); } .rotate-enter-active, .rotate-leave-active { transition: 0.5s; } .rotate-leave-to { transform: perspective(500px) rotate3d(0, 1, 0, -90deg); }

There are multiple ways to store these transition classes depending on your preferences and the needs of the project. The first, as mentioned earlier, is to keep it all in the style block of the app.vue file. You can also keep a Sass partial of all the transitions in the project’s assets folder and import it into the app’s style block.

<style lang="scss">   @import "assets/_transitions.scss"; </style>

This method allows for adjustments and additions to the collection of transitions outside of the Vue files. Another benefit of this setup is that such a file can be easily transferred between projects if they share transition effects. If one project gets a new transition, then it’s easy enough to transfer the addition to another project without having to touch main project files.

If you’re using CSS instead of Sass, then you can include the file as a requirement of the project. You can accomplish this by keeping the file in the assets folder of the project and placing a require statement in the main.js file.

require("@/assets/transitions.css");

Another option is keep the transition styles in a static CSS file that can be stored elsewhere, either in the public folder of the project or just on the server itself. Since this is a regular CSS file, no building or deployment would be required — just include a link reference in the index.html file.

<link rel="stylesheet" type="text/css" href="/css/transitions.css">

This file could also potentially be stored in a CDN for all projects to share. Whenever the file is updated, the changes are immediately available everywhere it is referenced. If a new transition name is created, then existing projects can start using the new name as needed.

Now, let’s slow down a minute

While we’re building a collection of transitions to use throughout our project, let’s consider users out there who may not want abrupt animations, or who may want no animations at all. Some people could consider our animations over-the-top and unnecessary, but for some, they can actually cause problems. Some time ago, WebKit introduced the prefers-reduced-motion media query to assist with possible Vestibular Spectrum Disorder issues. Eric Bailey also posted a nice introduction to the media query as well.

In most cases, adding the media query as part of our collection of transitions is quite easy and should be considered. We can either reduce the amount of motion involved in the transition to reduce the negative effects or simply turn them off.

Here’s a simple example from one of my demos below:

.next-enter {   opacity: 0;   transform: scale3d(2, 0.5, 1) translate3d(400px, 0, 0); }  .next-enter-to { transform: scale3d(1, 1, 1); } .next-enter-active, .next-leave-active { transition: 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55); } .next-leave { transform: scale3d(1, 1, 1); }  .next-leave-to {   opacity: 0;   transform: scale3d(2, 0.5, 1) translate3d(-400px, 0, 0); }  /* If animations are reduced at the OS level, use simpler transitions */ @media screen and (prefers-reduced-motion: reduce) {   .next-enter {     opacity: 0;     transform: translate3d(100px, 0, 0);   }    .next-enter-active,   .next-leave-active { transition: 0.5s; }    .next-leave-to {     opacity: 0;     transform: translate3d(-100px, 0, 0);   } }

In that example, I took what was a rather exaggerated transition and made it simpler. The animation is a slide that moves to the left with an elastic ease, then scales down and fades out as it moves away. If someone has the reduce motion preference set, then the animation becomes a much simpler transition with a shorter distance (which gives it a slower velocity) and keeps the fade. If we had wanted to turn them off, then we’d only need to reference the classes with the transition property and set their value to none.

To test this requires finding and selecting a checkbox on your respective OS. On Windows, you will find it in Control Panel > Ease of Access Center > Make the computer easier to see section; look for “Turn off all unnecessary animations (when possible).” On a Mac, look under System Preferences > Accessibility > Display; look for “Reduce motion.” The latest iOS devices have a similar setting under Accessibility as well.

Let’s stay flexible with our transitions collection

With this collection of transitions, there is the potential snag of a lack of flexibility with the effects. For instance, what if one element needs a slightly slower fade time? Let’s say that everything else in the effect can stay the same, only the transition-duration needs to be different. There are ways to adjust for that without having to create a whole new transition name.

The easiest method is to use an inline style directly on the element within the transition component.

<transition name="fade">   <div style="transition-duration: 6s;" v-if="isVisible">this has a different duration</div> </transition>

Such a change can also be done through the various ways Vue offers handling styles and classes.

Let’s say you are using the component element with the is attribute for dynamic components such as this:

<transition name="fade" mode="out-in">   <component :is="currentComponent"></component> </transition>

Even with this dynamic component, we have options to adjust properties of the transition effect. Again, we can apply an inline style on the component element, which will be placed on the root element of the component. The root element also receives the transition classes, so we would directly override their properties.

<transition name="fade" mode="out-in">   <component :is="currentComponent" style="transition-duration: 6s;"></component> </transition>

Another option is to pass in props to our components. That way, the desired changes can be applied through the component’s code to its root element.

<transition name="fade" mode="out-in">   <component :is="currentComponent" duration="6s"></component> </transition>
<template>   <div :style="`transition-duration: $  {duration}`">component one</div> </template>  <script> export default {   name: "component-one",   props: {     duration: String   } }; </script>

We can also override the properties of the transition’s classes inside the component’s style block, especially if it is scoped.

<style scoped>   .fade-enter-active,   .fade-leave-active { transition-duration: 1s; } </style>

In this case, the component will have a fade duration of one second instead of the global duration of half-a-second. We can even take it a step further and have different durations for each side of the sequence.

<style scoped>   .fade-enter-active { transition-duration: 1s; }   .fade-leave-active { transition-duration: 2s; } </style>

Any of the global transition classes can be altered within the component when needed. Although this isn’t quite as flexible as changing the property outside of a class structure, it can still be quite useful in certain circumstances.

As you can see, even with our collection of prebuilt transitions, we still have options for flexibility.

Dynamic transitions

Even after all these interesting things we can do with Vue’s transition component, yet another interesting feature waits to be explored. The name attribute on the transition component can be dynamic in nature, meaning we can change the current transition in use at will.

This means that the transition can be changed to have different animation effects with different situations, based in code. For example, we could have a transition change because of the answer to a question, transitions decided from user interaction, and have a list use different transitions based on the current state of the list itself.

Let’s look into these three examples.

Example 1: Change transition based on an answer

In this example, we have a simple math question that must be answered. Two numbers are randomly selected and we are expected to provide the sum. Then the button is clicked to check the answer against the expected answer. A small notification appears above the equation that indicates whether the answer is true or false. If the answer is correct, the notification is given a transition that suggests a head nodding yes with an up and down animation. If your answer is incorrect, the notification goes side-to-side suggesting a head shaking no.

See the Pen
VueJS Dynamic Transitions: Change Transition Based on an Answer
by Travis Almand (@talmand)
on CodePen.

The logic behind this is not overly complicated, nor is the setup of the transition. Here’s the HTML:

<transition :name="currentTransition">   <div id="notification" :class="response.toString()" v-if="answerChecked">{{ response }}</div> </transition>

Rather simple in nature. We have a bound name on the transition and then a v-if on the notification div. We also apply a true or false class to decorate the notification based on the response.

Here’s the CSS for the transitions:

.positive-enter-active { animation: positive 1s; } @keyframes positive {   0% { transform: translate3d(0, 0, 0); }   25% { transform: translate3d(0, -20px, 0); }   50% { transform: translate3d(0, 20px, 0); }   75% { transform: translate3d(0, -20px, 0); }   100% { transform: translate3d(0, 0, 0); } }  .negative-enter-active { animation: negative 1s; } @keyframes negative {   0% { transform: translate3d(0, 0, 0); }   25% { transform: translate3d(-20px, 0, 0); }   50% { transform: translate3d(20px, 0, 0); }   75% { transform: translate3d(-20px, 0, 0); }   100% { transform: translate3d(0, 0, 0); } }

You’ll see that I’m using CSS animations to accomplish the up-and-down and side-to-side effects.

Here’s some of the JavaScript:

methods: {   randomProblem: function () {     this.a = Math.floor(Math.random() * Math.floor(10));     this.b = Math.floor(Math.random() * Math.floor(10));   },   check: function () {     this.response = this.a + this.b === parseInt(this.answer);     this.answerChecked = true;     this.currentTransition = this.response ? 'positive' : 'negative';   },   reset: function () {     this.answer = null;     this.answerChecked = false;     this.randomProblem();   } }

There’s the randomProblem method that sets up our equation. The check method that decides on which transition effect to use based on comparing the provided answer with the correct answer. Then the simple reset method that just, well, resets everything.

This is just a simple example. Another possible example is having a notification that has two different effects based on whether the notification is important or not. If the message is not overly important, then we can have a subtle animation that doesn’t drive the user’s eyes away from the current task. If it is important, we could use an animation that is more direct in nature in an effort to force the eyes up to the notification.

Example 2: Change transition based on user interaction

Another thing we can build is a carousel of some sort. This could be presentation slides, an image gallery, or a series of instructions. The basic idea is that we have a need to present information to the user in a sequence. In this presentation, the user gets to decide when to proceed and whether to move forward or to go backward.

See the Pen
VueJS Dynamic Transitions: Change Transition Based on User Interaction
by Travis Almand (@talmand)
on CodePen.

This, again, is a rather simple setup. The example, more or less, is a slide presentation type of situation. The two buttons at the bottom shift between two components with a sliding transition. A real project would have more components or perhaps logic to change the contents of the components based on the current slide. This example shall stay simple to demonstrate the idea.

Here’s the HTML:

<transition :name="currentTransition" mode="out-in">   <component :is="slides[currentSlide]"></component> </transition>

You’ll see that we’re merely transitioning whenever the component is switched out by a bound is attribute on the component element.

Here’s the CSS:

.next-enter {   opacity: 0;   transform: scale3d(2, 0.5, 1) translate3d(400px, 0, 0); }  .next-enter-to { transform: scale3d(1, 1, 1); } .next-enter-active, .next-leave-active { transition: 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55); } .next-leave { transform: scale3d(1, 1, 1); }  .next-leave-to {   opacity: 0;   transform: scale3d(2, 0.5, 1) translate3d(-400px, 0, 0); }  .prev-enter {   opacity: 0;   transform: scale3d(2, 0.5, 1) translate3d(-400px, 0, 0); }  .prev-enter-to { transform: scale3d(1, 1, 1); } .prev-enter-active, .prev-leave-active { transition: 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55); } .prev-leave { transform: scale3d(1, 1, 1); }  .prev-leave-to {   opacity: 0;   transform: scale3d(2, 0.5, 1) translate3d(400px, 0, 0); }  /* If animations are reduced at the OS level, use simpler transitions */ @media screen and (prefers-reduced-motion: reduce) {   .next-enter { opacity: 0; transform: translate3d(100px, 0, 0); }   .next-enter-active,   .next-leave-active { transition: 0.5s; }   .next-leave-to { opacity: 0; transform: translate3d(-100px, 0, 0); }      .prev-enter { opacity: 0; transform: translate3d(-100px, 0, 0); }   .prev-enter-active,   .prev-leave-active { transition: 0.5s; }   .prev-leave-to { opacity: 0; transform: translate3d(100px, 0, 0); } }

Here we have two transitions, one for when the user clicks on the “next” button and the other is for the “prev” button. Each essentially slides the component in the appropriate direction with the transform property, but with a few extras to create a kind of squeezing effect for a cartoonish feel. We also make use of prefers-reduced-motion to change the animation to be a simpler fade with a small slide to the side in the appropriate direction.

Now, for the JavaScript:

methods: {   changeSlide: function (dir) {     this.currentSlide = dir === 'next' ? this.currentSlide + 1 : this.currentSlide - 1;     this.currentTransition = dir;   } }

Each button calls the changeSlide method on its click event and passes which direction it represents. Then we have some logic to keep track of what the current slide happens to be. A single line controls which transition to use. Since the “next” button passes “next” as the direction it corresponds to the “next” transition in the CSS. Same for the “prev” button. Each time the user clicks a button, the app automatically knows which transition to use. Thus, we have nice transition effects that provide context as to which direction the user is progressing through the sequence.

Example 3: Change transition based on list state

For our final example, we’ll see how to change transitions based on the current state of a list inside a transition-group component. The idea here is a list to be updated an item at a time with a different transition each time.

See the Pen
VueJS Dynamic Transitions: Change Transition Based on List State
by Travis Almand (@talmand)
on CodePen.

In this example, we are presented with a list of cities on the right and a blank list on the left. As cities are chosen on the right, they fill in the blanks on the left. The first city slides in from above while fading into view. The next cities before the last will slide in either from the right or the left, depending on the previous transition, and the last city slides in from below.

Here’s the HTML:

<transition-group :name="currentListTransition" tag="ul" class="list">   <li v-for="(item, index) in selectedItems" :key="item">{{ item }}</li> </transition-group>

As usual, a rather simple setup. Here are the transitions in CSS:

.top-enter-active, .top-leave-active { transition: 0.5s; } .top-enter, .top-leave-to {   opacity: 0;   transform: translate3d(0, -40px, 0); }  .top-move {   opacity: 0.5;   transition: 0.5s; }  .left-enter-active, .left-leave-active { transition: 0.5s; } .left-enter, .left-leave-to {   opacity: 0;   transform: translate3d(-40px, 0, 0); }  .left-move {   opacity: 0.5;   transition: 0.5s; }  .right-enter-active, .right-leave-active { transition: 0.5s; } .right-enter, .right-leave-to {   opacity: 0;   transform: translate3d(40px, 0, 0); }  .right-move {   opacity: 0.5;   transition: 0.5s; }  .bottom-enter-active, .bottom-leave-active { transition: 0.5s; } .bottom-enter, .bottom-leave-to {   opacity: 0;   transform: translate3d(0, 30px, 0); }  .bottom-move {   opacity: 0.5;   transition: 0.5s; }  /* If animations are reduced at the OS level, turn off transitions */ @media screen and (prefers-reduced-motion: reduce) {   .top-enter-active,   .top-leave-active { transition: none; }   .top-move { transition: none; }   .left-enter-active,   .left-leave-active { transition: none; }   .left-move { transition: none; }   .right-enter-active,   .right-leave-active { transition: none; }   .right-move { transition: none; }   .bottom-enter-active,   .bottom-leave-active { transition: none; }   .bottom-move { transition: none; } }

As you can see, a transition for each possible direction of the cities appearing the blank list.

Now, for our JavaScript:

methods: {   chooseCity: function (index) {     let selectedLength = this.selectedItems.length;     let citiesLength = this.cities.length;     let clt = this.currentListTransition;          if (selectedLength === 0) {       clt = 'top';     } else if (selectedLength > 0 && selectedLength < citiesLength - 1) {       clt = clt === 'top' || clt === 'left' ? 'right' : 'left';     } else if (selectedLength === citiesLength - 1) {       clt = 'bottom';     }          this.currentListTransition = clt;     this.selectedItems.push(this.cities[index]);     document.querySelector(`.city:nth-child($  {index + 1})`).classList.add('selected');   },    clearSelection: function () {     this.currentListTransition = 'right';     this.selectedItems = [];     document.querySelectorAll('.city.selected').forEach(element => {       element.classList.remove('selected');     });   } }

The chooseCity method handles what happens as you choose each city. What we mostly care about is the series of if and if/else statements in the middle of the method. As cities are selected, the logic looks at the current length of the selectedItems array that the selected cities eventually get pushed into. If the length is zero, then that’s the first city, so the transition should have it come in from the top. If the length is between zero and the total number of our cities list, then the transition should be right or left. The new direction used is based on the direction of the previous transition direction. Then, finally, if we’re on the last city to be chosen, it’ll change to the bottom transition. Again we use prefers-reduced-motion, in this case to turn off the transitions altogether.

Another option to change transitions for a list is changing according to the type of items chosen; such as east coast versus west coast cities, each having different transitions. Consider changing the transition based on the current number of items added to the list; for instance, a different transition for every five items.

So long, and thanks for all the transitions

After all these examples and ideas, I hope that you will consider leveraging Vue’s transition component in your own projects. Exploring the possibilities of adding transitions and animations to your apps to provide context and interest for your users. In many cases, additions such as these are rather simple to implement, almost to the point of it being a shame not to add them. Vue offers an exciting and highly useful feature, the transition component, out of the box and I can only encourage its usage.

Cheers.

The post The Power of Named Transitions in Vue appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]

A Website is a Car and Not a Book

I’ve been wondering for a good long while why it feels like web design and development isn’t respected as much as native app development= and why the front-end role in many organizations is seen as a nice-to-have rather than a vital part of the business. Why is it so hard to see that this gig we call “front-end development” is crucial for business and even the day-to-day lives of users?

Is it just me that feels this way?

We depend on front-end developers to help us file our taxes, buy our food and clothes, pay our bills, and entertain us. We find new music, we read stories and play games, and we fall in love… all on websites made up of nothing more than HTML, CSS, and JavaScript written by front-enders.

I’m not trying to be a jerk here, but you can see organizations everywhere that de-prioritize front-end development. There are slow websites! Ad-tech junk everywhere! Poor responsive interfaces! Divs used for buttons! Inaccessible forms! The problems on the web today are daunting and overwhelming to those who care about both good front-end development and the health of the web itself.

What’s the cause? Well, I certainly don’t believe that it’s malice. Nobody wants to make slow websites or broken interfaces and nobody (I think) is intentionally trying to break the web. So, why do we all end up doing things that go against what we know to be best practices? What is it about the complexities of web design that is so hard to grasp?

Again, I’m not being mean here – this is an honest question.

I got coffee with my pal Lindsay Grizzard the other day and we were talking about this stuff, asking each other these and other really tough questions related to our work. We both see problems in this industry and it drives us both a little mad to some extent.

Anyway, I asked Lindsay that question: what is it about web design that makes it so difficult to understand? She posited that the issue is that most people believe web design is like designing a book. Heck, we still call these things web pages. But Lindsay argued that building a modern website is nothing like designing a book; it’s more like designing a car.

Lindsay and I looked at the cars parked on the street next to us: they have to be mass produced and they have to be tested. Each has to be built up of perfectly identical components that need to fit together in a very specific format. There are technical issues – limitations of physics, money, and time – that require confronting on a daily basis. You can’t point at one part of the car and have an opinion about aesthetics because that one component changes the relationships of the others. You have to understand that you’re looking at an immensely complicated system of moving parts.

I love that comparison though, even if it’s not particularly helpful to give others insight into what we do: a website is a car and not a book.

The post A Website is a Car and Not a Book appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]