Why
You are walking around the Internet and sometimes come across extremely creative and smooth website interfaces, sliders, buttons, animations like Mobile App. Want to find out how they do it, but when viewing the Javascript source code, it has already been bundle. Or worse, WordPress with dozens of plugins.
I will tell you some very cool libraries to be able to manually make Smoothhh UI
Framer Motion
Homepage: https://www.framer.com/motion/
Doc: https://www.framer.com/api/motion
Guthub: https://github.com/framer/motion – 8.7k Stars
A library probably known as Dev ReactJS Native. This library was developed from Pose and on the homepage Pose also announced a redirect on Framer Motion. Framer is a UI / UX framework for App Mobile (Prototype), and they provide paid software but the library is completely free and Opensource.
Review
This is really an extremely easy to use library because all is wrapped in Components, all you have to do is choose color, shape, motion time … Very little code, just With 4 lines, you have a touch Animation. And of course, with the Mobile First criterion, this library is especially suitable when making App Mobile with drag and drop effects, swipe, touch and hold.
However, this is a limitation when you want to combine many effects at the same time, it will be really difficult to think in arrangement. Only one animation should be used for each object.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import { motion, useMotionValue, useTransform, } from "framer-motion" export const MyComponent = () => { const x = useMotionValue(0) const background = useTransform( x, [-100, 0, 100], ["#ff008c", "#7700ff", "rgb(230, 255, 0)"] ) return ( <motion.div style={{ background }}> <motion.div drag="x" dragConstraints={{ left: 0, right: 0 }} style={{ x }} > <Icon x={x} /> </motion.div> </motion.div> ) } |
Demo: https://codesandbox.io/s/framer-motion-path-drawing-drag-and-usetransform-jnqk2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import { motion } from "framer-motion" const variants = { open: { opacity: 1, x: 0 }, closed: { opacity: 0, x: "-100%" }, } export const MyComponent = () => { const [isOpen, setIsOpen] = useState(false) return ( <motion.nav animate={isOpen ? "open" : "closed"} variants={variants} > <Toggle onClick={() => setIsOpen(!isOpen)} /> <Items /> </motion.nav> ) } |
Demo: https://codesandbox.io/s/framer-motion-side-menu-mx2rw
React-spring
Homepage & Doc: https://www.react-spring.io/
Github: https://github.com/pmndrs/react-spring – 19k Stars
The new React-spring library has been developed since 2018. About its origin and father, please see the next section.
React-spring is a Spring-based Animation library (talking about repeating bounce) that will cover most of your UI / UX related Animation. It gives you tools flexible enough to execute all your ideas into smooth interfaces.
It’s heavily inspired by Christopher Chedeau’s animated and Cheng Lou’s react-motion Animation. It inherits animation’s powerful performance and interpolation, as well as the ease of use of reactive motion. You will be amazed how easily static data is converted to motion with small utility functions that don’t affect the way you view images.
Review
React-spring is much more primitive than Motion, and it takes a lot more time to learn and understand Keyframes. In return it also provides a lot of APIs to be used to make every Animation you can think of. Not many components, limited to the most basic forms of motion:
- useSpring
- useSprings
- useTrail
- useTransition
- useChain
But believe me, just use 3 out of 5 of these and your website will be dazzled
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import React from 'react' import { render } from 'react-dom' import { useTrail, animated } from 'react-spring' import './styles.css' const fast = { tension: 1200, friction: 40 } const slow = { mass: 10, tension: 200, friction: 50 } const trans = (x, y) => `translate3d(${x}px,${y}px,0) translate3d(-50%,-50%,0)` export default function Goo() { const [trail, set] = useTrail(3, () => ({ xy: [0, 0], config: i => (i === 0 ? fast : slow) })) return ( <> <svg style={{ position: 'absolute', width: 0, height: 0 }}> <filter id="goo"> <feGaussianBlur in="SourceGraphic" result="blur" stdDeviation="30" /> <feColorMatrix in="blur" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 30 -7" /> </filter> </svg> <div className="hooks-main" onMouseMove={e => set({ xy: [e.clientX, e.clientY] })}> {trail.map((props, index) => ( <animated.div key={index} style={{ transform: props.xy.interpolate(trans) }} /> ))} </div> </> ) } render(<Goo />, document.getElementById('root')) |
Demo: https://codesandbox.io/embed/8zx4ppk01l
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | // Original: https://github.com/chenglou/react-motion/tree/master/demos/demo8-draggable-list import { render } from 'react-dom' import React, { useRef } from 'react' import clamp from 'lodash-es/clamp' import swap from 'lodash-move' import { useGesture } from 'react-use-gesture' import { useSprings, animated, interpolate } from 'react-spring' import './styles.css' // Returns fitting styles for dragged/idle items const fn = (order, down, originalIndex, curIndex, y) => index => down && index === originalIndex ? { y: curIndex * 100 + y, scale: 1.1, zIndex: '1', shadow: 15, immediate: n => n === 'y' || n === 'zIndex' } : { y: order.indexOf(index) * 100, scale: 1, zIndex: '0', shadow: 1, immediate: false } function DraggableList({ items }) { const order = useRef(items.map((_, index) => index)) // Store indicies as a local ref, this represents the item order const [springs, setSprings] = useSprings(items.length, fn(order.current)) // Create springs, each corresponds to an item, controlling its transform, scale, etc. const bind = useGesture(({ args: [originalIndex], down, delta: [, y] }) => { const curIndex = order.current.indexOf(originalIndex) const curRow = clamp(Math.round((curIndex * 100 + y) / 100), 0, items.length - 1) const newOrder = swap(order.current, curIndex, curRow) setSprings(fn(newOrder, down, originalIndex, curIndex, y)) // Feed springs new style data, they'll animate the view without causing a single render if (!down) order.current = newOrder }) return ( <div className="content" style={{ height: items.length * 100 }}> {springs.map(({ zIndex, shadow, y, scale }, i) => ( <animated.div {...bind(i)} key={i} style={{ zIndex, boxShadow: shadow.interpolate(s => `rgba(0, 0, 0, 0.15) 0px ${s}px ${2 * s}px 0px`), transform: interpolate([y, scale], (y, s) => `translate3d(0,${y}px,0) scale(${s})`) }} children={items[i]} /> ))} </div> ) } render(<DraggableList items={'Lorem ipsum dolor sit'.split(' ')} />, document.getElementById('root')) |
Demo: https://codesandbox.io/embed/r5qmj8m6lq
This is the demo that convinced me to use React-spring.
React-motion
Github: https://github.com/chenglou/react-motion – 19k Stars
Review
If you look at the Document of this library, you will realize that React-spring is almost completely like. Exactly, the original purpose of Cheng Lou was to do a demo about managing the terminal state of moving object to provide an immediate experience to the User. About that, the community contributed and responded very well to this thinking, so they contributed to the birth of React-spring. The React-spring homepage also featured this video of him at React-Europe 2015.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | import createReactClass from 'create-react-class'; const Demo = createReactClass({ getInitialState() { return { items: [{key: 'a', size: 10}, {key: 'b', size: 20}, {key: 'c', size: 30}], }; }, componentDidMount() { this.setState({ items: [{key: 'a', size: 10}, {key: 'b', size: 20}], // remove c. }); }, willLeave() { // triggered when c's gone. Keeping c until its width/height reach 0. return {width: spring(0), height: spring(0)}; }, render() { return ( <TransitionMotion willLeave={this.willLeave} styles={this.state.items.map(item => ({ key: item.key, style: {width: item.size, height: item.size}, }))}> {interpolatedStyles => // first render: a, b, c. Second: still a, b, c! Only last one's a, b. <div> {interpolatedStyles.map(config => { return <div key={config.key} style={{...config.style, border: '1px solid'}} /> })} </div> } </TransitionMotion> ); }, }); |
If you are thinking that you have mastered when you can build a website in just a few weeks or days, it is still at the scale of 0.01 in the world. Consider whether it is 0.01s UI / UX, it will help level up that 100 times