Archiwum kategorii: CSS

Regarding CSS’s Global Scope

Post pobrano z: Regarding CSS’s Global Scope

html {
  font-family: Roboto, sans-serif;
}

With the except of some form elements, you’ve just set a font on every bit of text on a site! Nice! That’s probably what you were trying to do, because of the probably hundreds of elements all over your site, setting that font-family every time would be tedious and error-prone.

CSS is global by nature. On purpose!

I like how David Khourshid put it:

You ever stop and think about why CSS has a global scope? Maybe we want to use consistent typography, colors, sizing, spacing, layout, transitions, etc. and have our websites & apps feel like one cohesive unit?

Love the cascade, the cascade is your friend.

And yet. The global nature of CSS is perhaps the most-pointed-at anti-feature of CSS. Some people really don’t like it. We all know it’s very easy to write a single CSS rule that has implications all over a site, breaking things you really didn’t want to break.

Two CSS properties walk into a bar.

A barstool in a completely different bar falls over.

— Thomas Fuchs 🎄🕹💾 (@thomasfuchs) July 28, 2014

There are whole new categories of testing to assist with these problems.

Scoped styles aren’t the only reason there is such interest and adoption in the landscape of tools that is CSS-in-JS, but it’s a big one. There are loads of sites that don’t directly author any CSS at all — even preprocessed styles — and go for a JavaScript library instead where styles are authored quite literally in JavaScript. There is a playground demonstrating the syntax of the various options. Here’s how styled-components works:

import React from 'react';
import styled from 'styled-components';

const Container = styled.main`
  display: flex;
  flex-direction: column;
  min-height: 100%;
  width: 100%;
  background-color: #f6f9fc;
`;

export default function Login() {
  return (
    <Container>
      ... Some stuff ....
    </Container>
  );
}

There are literally dozens of options, each doing things a bit differently while offering slightly different syntaxes and features. Vue even offers scoped CSS directly in .vue files:

<style scoped>
.example {
  color: red;
}
</style>

<template>
  <div class="example">hi</div>
</template>

Unfortunately, <style scoped> never quite made it as a native web platform feature. There is shadow DOM, though, where a style block can be injected in a template and those styles will be isolated from the rest of the page:

let myElement = document.querySelector('.my-element');

let shadow = myElement.attachShadow({
  mode: 'closed'
});
shadow.innerHTML = `
  <style>
    p { 
      color: red;
    }
  </style>

  <p>Element with Shadow DOM</p>
`;

No styles will leak into or out of that shadow DOM boundary. That’s pretty cool for people seeking this kind of isolation, but it could be tricky. You’d likely have to architect the CSS to have certain global styles that can be imported with the shadow DOM’d web component so it can achieve some styling cohesion in your site. Personally, I wish it was possible to make the shadow DOM one-way permeable: styles can leak in, but styles defined inside can’t leak out.

CSS-in-JS stuff is only one way to scope styles. There are actually two sides to the spectrum. You could call CSS-in-JS total isolation, whereas you could author CSS directly with total abstraction:

Total abstraction might come from a project, like Tachyons, that gives you a fixed set of class names to use for styling (Tailwind is like a configurable version of that), or a programmatic tool (like Atomizer) that turns specially named HTML class attributes into a stylesheet with exactly what it needs.

Even adhering 100% to BEM across your entire site could be considered total CSS isolation, solving the problems that the global scope may bring.

Personally, I’d like to see us move to this kind of future:

When we write styles, we will always make a choice. Is this a global style? Am I, on purpose, leaking this style across the entire site? Or, am I writing CSS that is specific to this component? CSS will be split in half between these two. Component-specific styles will be scoped and bundled with the component and used as needed.

Best of both worlds, that.

Anyway, it’s tricky.

The problem is not CSS in JS.

It is CSS's global scope.

Solve the global scope, and CSS in JS will follow.

(I don't know if "follow" means disappear, being fully accepted, or getting a major overhaul.)

(For that matter, I don't know what "solving the global scope" means.)

— ppk 🇪🇺 (@ppk) November 28, 2018

Maybe this will be the hottest CSS topic in 2019.

The post Regarding CSS’s Global Scope appeared first on CSS-Tricks.

The Fragmented, But Evolving State of CSS-in-JS

Post pobrano z: The Fragmented, But Evolving State of CSS-in-JS

TLDR: The CSS-in-JS community has converged on a consistent API.

Not so long ago, a Facebook engineer compiled a list of the available CSS-in-JS methodologies. It wasn’t short:

aphrodite, babel-plugin-css-in-js, babel-plugin-pre-style, bloody-react-styled, classy, csjs, css-constructor, css-light, css-loader, css-ns, cssobj, cssx-loader, cxs, electron-css, emotion, es-css-modules, freestyler, glamor, glamorous, hiccup-css, hyperstyles, i-css, j2c, jsxstyle, linaria, nano-css, pre-style, radium, react-css-builder, react-css-components, react-css-modules, react-cssom, react-fela, react-free-style, react-inline-css, react-inline-style, react-inline, react-jss, react-look, react-native-web, react-statics-styles, react-styl, react-style, react-styleable, react-stylematic, react-theme, react-vstyle, reactcss, restyles, scope-styles, smart-css, stile-react-media-queries, stilr, stylable, style-it, styled-components, styled-jsx, styletron-react, styling, superstyle, typestyle, uranium

Such a fragmented ecosystem was far from appealing. Which one should you pick, (if any)?

Contributing to Javascript fatigue — you need at most one. Also feel free to not learn any.

GitHub stars are one useful metric:

However, GitHub stars say nothing about a project’s trajectory — perhaps they were accumulated long ago and the repo has since fallen out of favor or is no longer maintained. Glamor has plenty of open issues, and hasn’t seen a commit in over a year. Its author advises:

…it mostly works, I’m not going to do any major changes… if you need something more modern, I’d recommend emotion, it mostly matches glamor’s api, and is actively maintained.

The similarly named Glamorous was recently deprecated with its author also recommending users switch to Emotion:

At the time, Emotion had some features that Styled Components didn’t. Since then, Styled Components has made some big announcements.

Styled Components sells itself as the CSS-in-JS library for people that *like* CSS. Styled Components gained popularity by utilizing tagged template literals — allowing developers to *just write CSS* in the same syntax they already know, but inside JavaScript files. While this has proven popular, some developers prefer to [write styles as JavaScript objects. Emotion offered flexibility — developers could choose how to write their styles. Styled Components eventually followed suit.

styled-components v3.3.0 is out with first-class object support! 😍

Lots of people have been asking for this, your wishes have been heard! Shoutout to @probablyup for taking care of this release.

👉 https://t.co/yOHWg78nF4 pic.twitter.com/Ic8fZdAFVs

— Max Stoiber (@mxstbr) May 25, 2018

Emotion also offers a css prop, which Styled Components didn’t have, until…

🎉 Announcing support for the css prop in styled-components! 🎉

This has been a long time coming, hope y'all enjoy! ✨

👉 https://t.co/DMdrG6uviZ

Huge shoutout to @satya164 for coming up with the ingenious implementation! 👏

— Max Stoiber (@mxstbr) November 26, 2018

The rival CSS-in-JS libraries have stolen from each other until landing upon the same feature set and the same syntax — Emotion and Styled Components have an almost identical API. What once felt like a total mess of competing methodologies and libraries now feels somewhat stable. Even if CSS-in-JS hasn’t standardized on a dependency, it now has standardized a way of doing things — they’re just implemented differently:

Internally, quite a bit. SC has a lot of complexity around organizing style tag order.
Re css prop: SC requires Babel plugin and uses the entire SC custom component creation. Emotion will skip the custom component if it can and just renders the element with the className directly

— Kye Hohenberger (@tkh44) December 7, 2018

Styled Components is by far the most popular CSS-in-JS library, but Emotion has seen a rapid increase in usage.

Both are used by some major companies. Styled Components are utilized by plenty of large companies, including Bloomberg, Atlassian, Reddit, Target, BBC News, The Huffington Post, Coinbase, Patreon, Vogue, Ticketmaster, Lego, InVision and Autodesk just to name a few.

Emotion boasts fewer recognizable names, but has been recently adopted by the New York Times.

Great article about the launch of our new Story designs on the NYT today. It mentions our Shared Components initiative – would have been impossible without Emotion / CSS-in-JS. Absolute game-changer. Living in the future. https://t.co/pZLDJjsbEr

— Scott Taylor (@wonderboymusic) May 8, 2018


While these libraries certainly do seem to be most popular amongst React users, they can be used with other frameworks. While they seem to have converged on the same features at last, it’s difficult to say whether this is the end point of CSS-in-JS, or whether we’ll see a continued evolution from here.

The post The Fragmented, But Evolving State of CSS-in-JS appeared first on CSS-Tricks.

The Fragmented, But Evolving State of CSS-in-JS

Post pobrano z: The Fragmented, But Evolving State of CSS-in-JS

TLDR: The CSS-in-JS community has converged on a consistent API.

Not so long ago, a Facebook engineer compiled a list of the available CSS-in-JS methodologies. It wasn’t short:

aphrodite, babel-plugin-css-in-js, babel-plugin-pre-style, bloody-react-styled, classy, csjs, css-constructor, css-light, css-loader, css-ns, cssobj, cssx-loader, cxs, electron-css, emotion, es-css-modules, freestyler, glamor, glamorous, hiccup-css, hyperstyles, i-css, j2c, jsxstyle, linaria, nano-css, pre-style, radium, react-css-builder, react-css-components, react-css-modules, react-cssom, react-fela, react-free-style, react-inline-css, react-inline-style, react-inline, react-jss, react-look, react-native-web, react-statics-styles, react-styl, react-style, react-styleable, react-stylematic, react-theme, react-vstyle, reactcss, restyles, scope-styles, smart-css, stile-react-media-queries, stilr, stylable, style-it, styled-components, styled-jsx, styletron-react, styling, superstyle, typestyle, uranium

Such a fragmented ecosystem was far from appealing. Which one should you pick, (if any)?

Contributing to Javascript fatigue — you need at most one. Also feel free to not learn any.

GitHub stars are one useful metric:

However, GitHub stars say nothing about a project’s trajectory — perhaps they were accumulated long ago and the repo has since fallen out of favor or is no longer maintained. Glamor has plenty of open issues, and hasn’t seen a commit in over a year. Its author advises:

…it mostly works, I’m not going to do any major changes… if you need something more modern, I’d recommend emotion, it mostly matches glamor’s api, and is actively maintained.

The similarly named Glamorous was recently deprecated with its author also recommending users switch to Emotion:

At the time, Emotion had some features that Styled Components didn’t. Since then, Styled Components has made some big announcements.

Styled Components sells itself as the CSS-in-JS library for people that *like* CSS. Styled Components gained popularity by utilizing tagged template literals — allowing developers to *just write CSS* in the same syntax they already know, but inside JavaScript files. While this has proven popular, some developers prefer to [write styles as JavaScript objects. Emotion offered flexibility — developers could choose how to write their styles. Styled Components eventually followed suit.

styled-components v3.3.0 is out with first-class object support! 😍

Lots of people have been asking for this, your wishes have been heard! Shoutout to @probablyup for taking care of this release.

👉 https://t.co/yOHWg78nF4 pic.twitter.com/Ic8fZdAFVs

— Max Stoiber (@mxstbr) May 25, 2018

Emotion also offers a css prop, which Styled Components didn’t have, until…

🎉 Announcing support for the css prop in styled-components! 🎉

This has been a long time coming, hope y'all enjoy! ✨

👉 https://t.co/DMdrG6uviZ

Huge shoutout to @satya164 for coming up with the ingenious implementation! 👏

— Max Stoiber (@mxstbr) November 26, 2018

The rival CSS-in-JS libraries have stolen from each other until landing upon the same feature set and the same syntax — Emotion and Styled Components have an almost identical API. What once felt like a total mess of competing methodologies and libraries now feels somewhat stable. Even if CSS-in-JS hasn’t standardized on a dependency, it now has standardized a way of doing things — they’re just implemented differently:

Internally, quite a bit. SC has a lot of complexity around organizing style tag order.
Re css prop: SC requires Babel plugin and uses the entire SC custom component creation. Emotion will skip the custom component if it can and just renders the element with the className directly

— Kye Hohenberger (@tkh44) December 7, 2018

Styled Components is by far the most popular CSS-in-JS library, but Emotion has seen a rapid increase in usage.

Both are used by some major companies. Styled Components are utilized by plenty of large companies, including Bloomberg, Atlassian, Reddit, Target, BBC News, The Huffington Post, Coinbase, Patreon, Vogue, Ticketmaster, Lego, InVision and Autodesk just to name a few.

Emotion boasts fewer recognizable names, but has been recently adopted by the New York Times.

Great article about the launch of our new Story designs on the NYT today. It mentions our Shared Components initiative – would have been impossible without Emotion / CSS-in-JS. Absolute game-changer. Living in the future. https://t.co/pZLDJjsbEr

— Scott Taylor (@wonderboymusic) May 8, 2018


While these libraries certainly do seem to be most popular amongst React users, they can be used with other frameworks. While they seem to have converged on the same features at last, it’s difficult to say whether this is the end point of CSS-in-JS, or whether we’ll see a continued evolution from here.

The post The Fragmented, But Evolving State of CSS-in-JS appeared first on CSS-Tricks.

WooCommerce

Post pobrano z: WooCommerce

(This is a sponsored post.)

I just read a nicely put together story about WooCommerce over on the CodeinWP blog. WooCommerce started life as WooThemes, sort of a „premium themes” business started by just a couple of fellas who had never even met in person. Two years and a few employees later they launch WooCommerce, and 2 years after that it hits a million downloads. A major success story, to be sure, but a collaborative and remote-work based one that wasn’t exactly overnight. Another 2 years and Automattic picks them up and the WooThemes part is spun down.

Now we’re 3-4 years into WooCommerce being an Automattic project and it’s looking at nearly 60 million downloads, 4 million of which are active. A number they are saying is about 30% of all eCommerce on the web. Daaaaang. I’ve used WooCommerce a number of times and it always does a great job for me.

Direct Link to ArticlePermalink

The post WooCommerce appeared first on CSS-Tricks.

Animating Between Views in React

Post pobrano z: Animating Between Views in React

You know how some sites and web apps have that neat native feel when transitioning between two pages or views? Sarah Drasner has shown some good examples and even a Vue library to boot.

These animations are the type of features that can turn a good user experience into a great one. But to achieve this in a React stack, it is necessary to couple crucial parts in your application: the routing logic and the animation tooling.

Let’s start with animations. We’ll be building with React, and there are great options out there for us to leverage. Notably, the react-transition-group is the official package that handles elements entering and leaving the DOM. Let’s explore some relatively straightforward patterns we can apply, even to existing components.

Transitions using react-transition-group

First, let’s get familiar with the react-transition-group library to examine how we can use it for elements entering and leaving the DOM.

Single components transitions

As a simple example of a use case, we can try to animate a modal or dialog — you know, the type of element that benefits from animations that allow it enter and leave smoothly.

A dialog component might look something like this:

import React from "react";

class Dialog extends React.Component {
  render() {
    const { isOpen, onClose, message } = this.props;
    return (
      isOpen && (
        <div className="dialog--overlay" onClick={onClose}>
          <div className="dialog">{message}</div>
        </div>
      )
    );
  }
}

Notice we are using the isOpen prop to determine whether the component is rendered or not. Thanks to the simplicity of the recently modified API provided by react-transition-group module, we can add a CSS-based transition to this component without much overhead.

First thing we need is to wrap the entire component in another TransitionGroup component. Inside, we keep the prop to mount or unmount the dialog, which we are wrapping in a CSSTransition.

import React from "react";
import { TransitionGroup, CSSTransition } from "react-transition-group";

class Dialog extends React.Component {
  render() {
    const { isOpen, onClose, message } = this.props;
    return (
      <TransitionGroup component={null}>
        {isOpen && (
          <CSSTransition classNames="dialog" timeout={300}>
            <div className="dialog--overlay" onClick={onClose}>
              <div className="dialog">{message}</div>
            </div>
          </CSSTransition>
        )}
      </TransitionGroup>
    );
  }
}

Every time isOpen is modified, a sequence of class names changes will happen in the dialog’s root element.

If we set the classNames prop to "fade", then fade-enter will be added immediately before the element mounts and then fade-enter-active when the transition kicks off. We should see fade-enter-done when the transition finishes, based on the timeout that was set. Exactly the same will happen with the exit class name group at the time the element is about to unmount.

This way, we can simply define a set of CSS rules to declare our transitions.

.dialog-enter {
  opacity: 0.01;
  transform: scale(1.1);
}

.dialog-enter-active {
  opacity: 1;
  transform: scale(1);
  transition: all 300ms;
}

.dialog-exit {
  opacity: 1;
  transform: scale(1);
}

.dialog-exit-active {
  opacity: 0.01;
  transform: scale(1.1);
  transition: all 300ms;
}

JavaScript Transitions

If we want to orchestrate more complex animations using a JavaScript library, then we can use the Transition component instead.

This component doesn’t do anything for us like the CSSTransition did, but it does expose hooks on each transition cycle. We can pass methods to each hook to run calculations and animations.

<TransitionGroup component={null}>
  {isOpen && (
    <Transition
      onEnter={node => animateOnEnter(node)}
      onExit={node => animateOnExit(node)}
      timeout={300}
    >
      <div className="dialog--overlay" onClick={onClose}>
        <div className="dialog">{message}</div>
      </div>
    </Transition>
  )}
</TransitionGroup>

Each hook passes the node to the callback as a first argument — this gives control for any mutation we want when the element mounts or unmounts.

Routing

The React ecosystem offers plenty of router options. I’m gonna use react-router-dom since it’s the most popular choice and because most React developers are familiar with the syntax.

Let’s start with a basic route definition:

import React, { Component } from 'react'
import { BrowserRouter, Switch, Route } from 'react-router-dom'
import Home from '../views/Home'
import Author from '../views/Author'
import About from '../views/About'
import Nav from '../components/Nav'

class App extends Component {
  render() {
    return (
      <BrowserRouter>
        <div className="app">
          <Switch>
            <Route exact path="/" component={Home}/>
            <Route path="/author" component={Author} />
            <Route path="/about" component={About} />
          </Switch>
        </div>
      </BrowserRouter>
    )
  }
}

We want three routes in this application: home, author and about.

The BrowserRouter component handles the browser’s history updates, while Switch decides which Route element to render depending on the path prop. Here’s that without any transitions:

Don’t worry, we’ll be adding in page transitions as we go.

Oil and water

While both react-transition-group and react-router-dom are great and handy packages for their intended uses, mixing them together can break their functionality.

For example, the Switch component in react-router-dom expects direct Route children and the TransitionGroup components in react-transition-group expect CSSTransition or Transition components to be direct children of it too. So, we’re unable to wrap them the way we did earlier.

We also cannot toggle views with the same boolean approach as before since it’s handled internally by the react-router-dom logic.

React keys to the rescue

Although the solution might not be as clean as our previous examples, it is possible to use the libraries together. The first thing we need to do is to move our routes declaration to a render prop.

<BrowserRouter>
  <div className="app">
    <Route render={(location) => {
      return (
        <Switch location={location}>
          <Route exact path="/" component={Home}/>
          <Route path="/author" component={Author} />
          <Route path="/about" component={About} />
        </Switch>
      )}
    />
</BrowserRouter>

Nothing has changed as far as functionality. The difference is that we are now in control of what gets rendered every time the location in the browser changes.

Also, react-router-dom provides a unique key in the location object every time this happens.

In case you are not familiar with them, React keys identify elements in the virtual DOM tree. Most times, we don’t need to indicate them since React will detect which part of the DOM should change and then patch it.

<Route render={({ location }) => {
  const { pathname, key } = location

  return (
    <TransitionGroup component={null}>
      <Transition
        key={key}
        appear={true}
        onEnter={(node, appears) => play(pathname, node, appears)}
        timeout={{enter: 750, exit: 0}}
      >
        <Switch location={location}>
          <Route exact path="/" component={Home}/>
          <Route path="/author" component={Author} />
          <Route path="/about" component={About} />
        </Switch>
      </Transition>
    </TransitionGroup>
  )
}}/>

Constantly changing the key of an element — even when its children or props haven’t been modified — will force React to remove it from the DOM and remount it. This helps us emulate the boolean toggle approach we had before and it’s important for us here because we can place a single Transition element and reuse it for all of our view transitions, allowing us to mix routing and transition components.

Inside the animation function

Once the transition hooks are called on each location change, we can run a method and use any animation library to build more complex scenes for our transitions.

export const play = (pathname, node, appears) => {
  const delay = appears ? 0 : 0.5
  let timeline

  if (pathname === '/')
    timeline = getHomeTimeline(node, delay)
  else
    timeline = getDefaultTimeline(node, delay)

  timeline.play()
}

Our play function will build a GreenSock timeline here depending on the pathname, and we can set as many transitions as we want for each different routes.

Once the timeline is built for the current pathname, we play it.

const getHomeTimeline = (node, delay) => {
  const timeline = new Timeline({ paused: true });
  const texts = node.querySelectorAll('h1 > div');

  timeline
    .from(node, 0, { display: 'none', autoAlpha: 0, delay })
    .staggerFrom(texts, 0.375, { autoAlpha: 0, x: -25, ease: Power1.easeOut }, 0.125);

  return timeline
}

Each timeline method digs into the DOM nodes of the view and animates them. You can use other animation libraries instead of GreenSock, but the important detail is that we build the timeline beforehand so that our main play method can decide which one should run for each route.

Success!

I’ve used this approach on lots of projects, and though it doesn’t present obvious performance issues for inner navigations, I did notice a concurrency issue between the browser’s initial DOM tree build and the first route animation. This caused a visual lag on the animation for the first load of the application.

To make sure animations are smooth in each stage of the application, there’s one last thing we can do.

Profiling the initial load

Here’s what I found when auditing the application in Chrome DevTools after a hard refresh:

You can see two lines: one blue and one red. Blue represents the load event and red the DOMContentLoaded. Both intersect the execution of the initial animations.

These lines are indicating that elements are animating while the browser hasn’t yet finished building the entire DOM tree or it’s parsing resources. Animations account for big performance hits. If we want anything else to happen, we’d have to wait for the browser to be ready with these heavy and important tasks before running our transitions.

After trying a lot of different approaches, the solution that actually worked was to move the animation after these events — simple as that. The issue is that we can’t rely on event listeners.

window.addEventListener(‘DOMContentLoaded’, () => {
  timeline.play()
})

If for some reason, the event occurs before we declare the listener, the callback we pass will never run and this could lead to our animations never happening and an empty view.

Since this is a concurrency and asynchronous issue, I decided to rely on promises, but then the question became: how can promises and event listeners be used together?

By creating a promise that gets resolved when the event takes place. That’s how.

window.loadPromise = new Promise(resolve => {
  window.addEventListener(‘DOMContentLoaded’, resolve)
})

We can put this in the document head or just before the script tag that loads the application bundle. This will make sure the event never happens before the Promise is created.

Plus, doing this allows us to use the globally exposed loadPromise to any animation in our application. Let’s say that we don’t only want to animate the entry view but a cookie banner or the header of the application. We can simply call each of these animations after the promise has resolved using then along with our transitions.

window.loadPromise.then(() => timeline.play())

This approach is reusable across the entire codebase, eliminating the issue that would result when an event gets resolved before the animations run. It will defer them until the browser DOMContentLoaded event has passed.

See now that the animation is not kicking off until the red line appears.

The difference is not only on the profiling report — it actually solves an issue we had in a real project.

Wrapping up

In order to act as reminders, I created a list of tips for me that you might find useful as you dig into view transitions in a project:

  • When an animation is happening nothing else should be happening. Run animations after all resources, fetching and business logic have completed.
  • No animation is better than crappy animations If you can’t achieve a good animation, then removing it is a fair sacrifice. The content is more important and showing it is the priority until a good animation solution is in place.
  • Test on slower and older devices. They will make it easier for you to catch spots with weak performance.
  • Profile and base your improvements in metrics. Instead of guessing as you go, like I did, see if you can spot where frames are being dropped or if something looks off and attack that issue first.

That’s it! Best of luck with animating view transitions. Please post a comment if this sparked any questions or if you have used transitions in your app that you’d like to share!

The post Animating Between Views in React appeared first on CSS-Tricks.

Animating Between Views in React

Post pobrano z: Animating Between Views in React

You know how some sites and web apps have that neat native feel when transitioning between two pages or views? Sarah Drasner has shown some good examples and even a Vue library to boot.

These animations are the type of features that can turn a good user experience into a great one. But to achieve this in a React stack, it is necessary to couple crucial parts in your application: the routing logic and the animation tooling.

Let’s start with animations. We’ll be building with React, and there are great options out there for us to leverage. Notably, the react-transition-group is the official package that handles elements entering and leaving the DOM. Let’s explore some relatively straightforward patterns we can apply, even to existing components.

Transitions using react-transition-group

First, let’s get familiar with the react-transition-group library to examine how we can use it for elements entering and leaving the DOM.

Single components transitions

As a simple example of a use case, we can try to animate a modal or dialog — you know, the type of element that benefits from animations that allow it enter and leave smoothly.

A dialog component might look something like this:

import React from "react";

class Dialog extends React.Component {
  render() {
    const { isOpen, onClose, message } = this.props;
    return (
      isOpen && (
        <div className="dialog--overlay" onClick={onClose}>
          <div className="dialog">{message}</div>
        </div>
      )
    );
  }
}

Notice we are using the isOpen prop to determine whether the component is rendered or not. Thanks to the simplicity of the recently modified API provided by react-transition-group module, we can add a CSS-based transition to this component without much overhead.

First thing we need is to wrap the entire component in another TransitionGroup component. Inside, we keep the prop to mount or unmount the dialog, which we are wrapping in a CSSTransition.

import React from "react";
import { TransitionGroup, CSSTransition } from "react-transition-group";

class Dialog extends React.Component {
  render() {
    const { isOpen, onClose, message } = this.props;
    return (
      <TransitionGroup component={null}>
        {isOpen && (
          <CSSTransition classNames="dialog" timeout={300}>
            <div className="dialog--overlay" onClick={onClose}>
              <div className="dialog">{message}</div>
            </div>
          </CSSTransition>
        )}
      </TransitionGroup>
    );
  }
}

Every time isOpen is modified, a sequence of class names changes will happen in the dialog’s root element.

If we set the classNames prop to "fade", then fade-enter will be added immediately before the element mounts and then fade-enter-active when the transition kicks off. We should see fade-enter-done when the transition finishes, based on the timeout that was set. Exactly the same will happen with the exit class name group at the time the element is about to unmount.

This way, we can simply define a set of CSS rules to declare our transitions.

.dialog-enter {
  opacity: 0.01;
  transform: scale(1.1);
}

.dialog-enter-active {
  opacity: 1;
  transform: scale(1);
  transition: all 300ms;
}

.dialog-exit {
  opacity: 1;
  transform: scale(1);
}

.dialog-exit-active {
  opacity: 0.01;
  transform: scale(1.1);
  transition: all 300ms;
}

JavaScript Transitions

If we want to orchestrate more complex animations using a JavaScript library, then we can use the Transition component instead.

This component doesn’t do anything for us like the CSSTransition did, but it does expose hooks on each transition cycle. We can pass methods to each hook to run calculations and animations.

<TransitionGroup component={null}>
  {isOpen && (
    <Transition
      onEnter={node => animateOnEnter(node)}
      onExit={node => animateOnExit(node)}
      timeout={300}
    >
      <div className="dialog--overlay" onClick={onClose}>
        <div className="dialog">{message}</div>
      </div>
    </Transition>
  )}
</TransitionGroup>

Each hook passes the node to the callback as a first argument — this gives control for any mutation we want when the element mounts or unmounts.

Routing

The React ecosystem offers plenty of router options. I’m gonna use react-router-dom since it’s the most popular choice and because most React developers are familiar with the syntax.

Let’s start with a basic route definition:

import React, { Component } from 'react'
import { BrowserRouter, Switch, Route } from 'react-router-dom'
import Home from '../views/Home'
import Author from '../views/Author'
import About from '../views/About'
import Nav from '../components/Nav'

class App extends Component {
  render() {
    return (
      <BrowserRouter>
        <div className="app">
          <Switch>
            <Route exact path="/" component={Home}/>
            <Route path="/author" component={Author} />
            <Route path="/about" component={About} />
          </Switch>
        </div>
      </BrowserRouter>
    )
  }
}

We want three routes in this application: home, author and about.

The BrowserRouter component handles the browser’s history updates, while Switch decides which Route element to render depending on the path prop. Here’s that without any transitions:

Don’t worry, we’ll be adding in page transitions as we go.

Oil and water

While both react-transition-group and react-router-dom are great and handy packages for their intended uses, mixing them together can break their functionality.

For example, the Switch component in react-router-dom expects direct Route children and the TransitionGroup components in react-transition-group expect CSSTransition or Transition components to be direct children of it too. So, we’re unable to wrap them the way we did earlier.

We also cannot toggle views with the same boolean approach as before since it’s handled internally by the react-router-dom logic.

React keys to the rescue

Although the solution might not be as clean as our previous examples, it is possible to use the libraries together. The first thing we need to do is to move our routes declaration to a render prop.

<BrowserRouter>
  <div className="app">
    <Route render={(location) => {
      return (
        <Switch location={location}>
          <Route exact path="/" component={Home}/>
          <Route path="/author" component={Author} />
          <Route path="/about" component={About} />
        </Switch>
      )}
    />
</BrowserRouter>

Nothing has changed as far as functionality. The difference is that we are now in control of what gets rendered every time the location in the browser changes.

Also, react-router-dom provides a unique key in the location object every time this happens.

In case you are not familiar with them, React keys identify elements in the virtual DOM tree. Most times, we don’t need to indicate them since React will detect which part of the DOM should change and then patch it.

<Route render={({ location }) => {
  const { pathname, key } = location

  return (
    <TransitionGroup component={null}>
      <Transition
        key={key}
        appear={true}
        onEnter={(node, appears) => play(pathname, node, appears)}
        timeout={{enter: 750, exit: 0}}
      >
        <Switch location={location}>
          <Route exact path="/" component={Home}/>
          <Route path="/author" component={Author} />
          <Route path="/about" component={About} />
        </Switch>
      </Transition>
    </TransitionGroup>
  )
}}/>

Constantly changing the key of an element — even when its children or props haven’t been modified — will force React to remove it from the DOM and remount it. This helps us emulate the boolean toggle approach we had before and it’s important for us here because we can place a single Transition element and reuse it for all of our view transitions, allowing us to mix routing and transition components.

Inside the animation function

Once the transition hooks are called on each location change, we can run a method and use any animation library to build more complex scenes for our transitions.

export const play = (pathname, node, appears) => {
  const delay = appears ? 0 : 0.5
  let timeline

  if (pathname === '/')
    timeline = getHomeTimeline(node, delay)
  else
    timeline = getDefaultTimeline(node, delay)

  timeline.play()
}

Our play function will build a GreenSock timeline here depending on the pathname, and we can set as many transitions as we want for each different routes.

Once the timeline is built for the current pathname, we play it.

const getHomeTimeline = (node, delay) => {
  const timeline = new Timeline({ paused: true });
  const texts = node.querySelectorAll('h1 > div');

  timeline
    .from(node, 0, { display: 'none', autoAlpha: 0, delay })
    .staggerFrom(texts, 0.375, { autoAlpha: 0, x: -25, ease: Power1.easeOut }, 0.125);

  return timeline
}

Each timeline method digs into the DOM nodes of the view and animates them. You can use other animation libraries instead of GreenSock, but the important detail is that we build the timeline beforehand so that our main play method can decide which one should run for each route.

Success!

I’ve used this approach on lots of projects, and though it doesn’t present obvious performance issues for inner navigations, I did notice a concurrency issue between the browser’s initial DOM tree build and the first route animation. This caused a visual lag on the animation for the first load of the application.

To make sure animations are smooth in each stage of the application, there’s one last thing we can do.

Profiling the initial load

Here’s what I found when auditing the application in Chrome DevTools after a hard refresh:

You can see two lines: one blue and one red. Blue represents the load event and red the DOMContentLoaded. Both intersect the execution of the initial animations.

These lines are indicating that elements are animating while the browser hasn’t yet finished building the entire DOM tree or it’s parsing resources. Animations account for big performance hits. If we want anything else to happen, we’d have to wait for the browser to be ready with these heavy and important tasks before running our transitions.

After trying a lot of different approaches, the solution that actually worked was to move the animation after these events — simple as that. The issue is that we can’t rely on event listeners.

window.addEventListener(‘DOMContentLoaded’, () => {
  timeline.play()
})

If for some reason, the event occurs before we declare the listener, the callback we pass will never run and this could lead to our animations never happening and an empty view.

Since this is a concurrency and asynchronous issue, I decided to rely on promises, but then the question became: how can promises and event listeners be used together?

By creating a promise that gets resolved when the event takes place. That’s how.

window.loadPromise = new Promise(resolve => {
  window.addEventListener(‘DOMContentLoaded’, resolve)
})

We can put this in the document head or just before the script tag that loads the application bundle. This will make sure the event never happens before the Promise is created.

Plus, doing this allows us to use the globally exposed loadPromise to any animation in our application. Let’s say that we don’t only want to animate the entry view but a cookie banner or the header of the application. We can simply call each of these animations after the promise has resolved using then along with our transitions.

window.loadPromise.then(() => timeline.play())

This approach is reusable across the entire codebase, eliminating the issue that would result when an event gets resolved before the animations run. It will defer them until the browser DOMContentLoaded event has passed.

See now that the animation is not kicking off until the red line appears.

The difference is not only on the profiling report — it actually solves an issue we had in a real project.

Wrapping up

In order to act as reminders, I created a list of tips for me that you might find useful as you dig into view transitions in a project:

  • When an animation is happening nothing else should be happening. Run animations after all resources, fetching and business logic have completed.
  • No animation is better than crappy animations If you can’t achieve a good animation, then removing it is a fair sacrifice. The content is more important and showing it is the priority until a good animation solution is in place.
  • Test on slower and older devices. They will make it easier for you to catch spots with weak performance.
  • Profile and base your improvements in metrics. Instead of guessing as you go, like I did, see if you can spot where frames are being dropped or if something looks off and attack that issue first.

That’s it! Best of luck with animating view transitions. Please post a comment if this sparked any questions or if you have used transitions in your app that you’d like to share!

The post Animating Between Views in React appeared first on CSS-Tricks.

Annotated Build Processes

Post pobrano z: Annotated Build Processes

When you’re putting together a build process for a site, it’s so dang useful to look at other people’s processes. I ran across Andrew Welch’s „An Annotated webpack 4 Config for Frontend Web Development” the other day and was glad he blogged it. If I was kicking off a new site where I wanted a webpack build, then I’d almost certainly reference something like this rather than start from scratch. At the same time, it made me realize how build processes all have such different needs and how unique those needs are now from even a few years ago in the hay day of Grunt and Gulp build processes.

I was looking around for an annotated Gulp reference file and came across another one of Andrew’s articles — „A Gulp Workflow for Frontend Development Automation” — from just one year earlier! Here’s a simplified list of what he was doing with Gulp (which he explains in more detail in the post):

  • Compile Sass
  • Run Autoprefixer
  • Create Sourcemaps
  • Minify
  • Inject critical CSS and bits of scripts
  • Run Babel
  • Uglify
  • Do style injection/reloading
  • Run accessibility audit</li
  • Generate icon font
  • Optimize images

Speaking of Gulp and annotated build processes, I’m working on a CSS-Tricks redesign and, for various reasons, went with a Gulp build. Against my better judgment, I wrote it from scratch, and this is how far I’ve gotten. It doesn’t feel particularly robust or efficient, so rewrites and suggestions are welcome! And speaking of Gulp, here’s a recently-published boilerplate I wish I had seen before starting.

Now, a year later, here’s what the build process is being asked to do:

  • Run differently-configured web servers
  • Hot module replacement
  • Dynamic code splitting
  • Lazy loading
  • Make modern and legacy code bundles
  • Cache busting
  • Create service worker
  • Compile PostCSS
  • Optimize images / create .webp
  • Process .vue files
  • Run Tailwind and PurgeCSS

It’s funny how quickly things change. We’re still essentially asking for help compiling files and optimizing things, but the tools we use change, the code we write changes, the way we talk about development changes, the expectations of development changes, the best practices change… makes ya sweat. 😅

The post Annotated Build Processes appeared first on CSS-Tricks.

Making SVG icon libraries for React apps

Post pobrano z: Making SVG icon libraries for React apps

Nicolas Gallagher:

At Twitter I used the approach described here to publish the company’s SVG icon library in several different formats: optimized SVGs, plain JavaScript modules, React DOM components, and React Native components.

There is no One True Way© to make an SVG icon system. The only thing that SVG icon systems have in common is that, somehow, some way, SVG is used to show that icon. I gotta find some time to write up a post that goes into all the possibilities there.

One thing different systems tend to share is some kind of build process to turn a folder full of SVG files into a more programmatically digestible format. For example, gulp-svg-sprite takes your folder of SVGs and creates a SVG sprite (chunk of <symbol>s) to use in that type of SVG icon system. Grunticon processes your folder of SVGs into a CSS file, and is capable of enhancing them into inline SVG. Gallagher’s script creates React components out of them, and like he said, that’s great for delivery to different targets as well as performance optimization, like code splitting.

This speaks to the versatility of SVG. It’s just markup, so it’s easy to work with.

Direct Link to ArticlePermalink

The post Making SVG icon libraries for React apps appeared first on CSS-Tricks.

Two Ways to Build a Site That Seem Super Different But Weirdly Aren’t That Different

Post pobrano z: Two Ways to Build a Site That Seem Super Different But Weirdly Aren’t That Different

Here are two ways to build a site (abstractly) that feel diametrically opposed to me:

  1. Build a site as an SPA (Single Page App). The page loads a skeleton HTML page that executes JavaScript as quickly as it can. The JavaScript calls an API to get data, and then the page renders content. Navigation of the site is more API calls to get the data it needs and re-rendering.
  2. Build a site as statically-generated. A build process runs in which the entire site is built out as static HTML files with all the content baked into them. JavaScript isn’t required at all for the site to work.

That feels just about as different as can be. But weirdly, they kinda aren’t:

  1. They are both JAMstack. They can be hosted statically as neither of them needs backend languages running on the server they are hosted on.
  2. They are both building content based on an API of data. It’s more obvious in the first one, but you can think of a static site generator as hitting an API of data as it runs and builds itself. It’s just that the API might be temporarily created from content files it finds on disk. Or it might be the exact same API used for the former site.

That’s all.

The post Two Ways to Build a Site That Seem Super Different But Weirdly Aren’t That Different appeared first on CSS-Tricks.

JavaScript to Native (and Back!)

Post pobrano z: JavaScript to Native (and Back!)

I admit I’m quite intrigued by frameworks that allow you write apps in web frameworks because they do magic to make them into native apps for you. There are loads of players here. You’ve got NativeScript, Cordova, PhoneGap, Tabris, React Native, and Flutter. For deskop apps, we’ve got Electron.

What’s interesting now is to see what’s important to these frameworks by honing in on their focus. Hummingbird is Flutter for the web. (There is a fun series on Flutter over on the Bendworks blog in addition to a post we published earlier this year.) The idea being you get super high performance ,thanks to the framework, and you’ve theoretically built one app that runs both on the web and natively. I don’t know of any real success stories I can point to, but it does seem like an awesome possibility.

Nicolas Gallagher has been a strong proponent of React Native for the web.

The post JavaScript to Native (and Back!) appeared first on CSS-Tricks.