gif of matrix transforms updating with dev tools open
Strategy

Making a lil’ me – Part 1.


I’m so excited to have finally launched my website.

This was one of my favourite bits to make by far. A little animated me that responds to the cursor position.

See the Pen lil’ me. by Cassie Evans (@cassie-codes) on CodePen.

In this post we’ll cover how to get values from the mouse movement and plug them into an animation.

This is my favourite thing about SVG animation. Not mouse movement in particular, but interactivity. Exporting animation as an mp4 is cool and all. But you can’t play with it.

Animating on the web opens up so many cool possibilities!

If you’re the kind of person who learns best by digging into the code, then just go ahead and fork that pen, have fun!


Still here? 😊 Cool beans, let’s go through it together.

I use Greensock for all my SVG animation. There are a few reasons for this. Firstly, it gives you more control and is super fun to use. But more importantly, as browsers implement the SVG spec differently, animating can get a bit messy. The team at Greensock put a lot of effort into harmonizing behavior across browsers.

Under the hood though, Greensock is just a really performant property manipulator. It will manipulate (pretty much) whatever value you want to change. In this case it’s updating the values in a matrix transform. Check this out.

gif of matrix transforms updating with dev tools open

Cool right! Greensock is great at this kind of thing, but there’s a lot going on in this pen, so let’s break it down into chunks and focus on one bit at a time. First up, the mouse interaction. We’ll come back to Greensock in a bit!

Mouse movement fun! permalink

So, there’s another way we can modify values in CSS with Javascript. CSS custom properties!

See the Pen Mouse movement demo by Cassie Evans (@cassie-codes) on CodePen.

Let’s walk through the process. The goal is to get the x and y position of the cursor as we move our mouse about, and then we can use those values to update some custom properties.

In the previous gif Greensock is using matrix transforms, which are more performant. But we’re going to use transform: translate(x,y) for this as it’s a tad more readable, and we can use percentage values.

First up, we declare some custom properties for the x and y values and then use those custom properties in place of regular property values in our transform.

:root {
--mouse-x: 0;
--mouse-y: 0;
}

.pointer {
transform: translate(var(--mouse-x), var(--mouse-y));
}

Then we need to get our mouse coordinates. We can do this by listening to the mouse movement and getting the mouse’s coordinates with clientX and clientY

We’ll assign those values to some global variables so that we can access them in another function later.

let xPosition;
let yPosition;


function updateMouseCoords(event) {
xPosition = event.clientX;
yPosition = event.clientY;
}
window.addEventListener('mousemove', updateMouseCoords);

Now we’ve got our coordinates, lets use them to update our custom properties and move our pointer around!

😇 When animating things on the web it’s important to pay attention to performance. We can’t know for sure how many times a users mouse event will fire as it’s implementation specific. If it fires more than 60 times per second (which is the average refresh rate for most browsers) we’ll end up with unnecessary computation. So to avoid burning up everyone’s laptop fans and melting their CPU we can use requestAnimationFrame

Request animation frame allows us to make smoother, browser optimized animations. If the user changes tabs, the animation will stop and give the CPU a break. You call the function once to start, and then it recusively calls itself.

⚠️ This is a great way to crash your browser if you get some code wrong!

function movePointer() {

requestAnimationFrame(movePointer);
}
requestAnimationFrame(movePointer);

Right now, the x and y position we’re getting back from event.clientX and event.clientY are pixel values, this isn’t really useful to us. If we plug them straight into our custom properties we could end up transforming our pointer hundreds of pixels off in one direction.

See the Pen Mouse movement demo by Cassie Evans (@cassie-codes) on CodePen.

We need to convert those pixel values into percentages of the window height and width.

Let’s define some global variables for the window width and height and work out the percentage values.

let windowHeight = window.innerHeight;
let windowWidth = window.innerWidth;

function percentage(partialValue, totalValue) {
return (100 * partialValue) / totalValue;
}

function movePointer() {
x = percentage(xPosition, windowWidth);
y = percentage(yPosition, windowHeight);

window.requestAnimationFrame(movePointer);
}
requestAnimationFrame(movePointer);

This will give us a range from 0 – 100, which would just move our pointer downwards and to the right, so we can shift the range by subtracting 50.

Once we’ve got our nice centralised range, we can plug it into our custom properties using setProperty()

let windowHeight = window.innerHeight;
let windowWidth = window.innerWidth;

function percentage(partialValue, totalValue) {
return (100 * partialValue) / totalValue;
}

function movePointer() {


x = percentage(xPosition, windowWidth) - 50;
y = percentage(yPosition, windowHeight) - 50;


document.documentElement.style.setProperty('--mouse-x', `${x}%`);
document.documentElement.style.setProperty('--mouse-y', `${y}%`);

window.requestAnimationFrame(movePointer);
}
requestAnimationFrame(movePointer);

The user might resize the browser, so it’s good to check for that.


function updateWindowSize() {
windowHeight = window.innerHeight;
windowWidth = window.innerWidth;
}
window.addEventListener('resize', updateWindowSize);

We can also avoid unnecessary calculations when the mouse position hasn’t changed by storing past x and y positions and comparing them to the new positions.

let xPosition;
let yPosition;

let storedXPosition;
let storedYPosition;

function movePointer() {
window.requestAnimationFrame(movePointer);

if (storedXPosition === xPosition && storedYPosition === yPosition) return;




storedXPosition = xPosition;
storedYPosition = yPosition;
}

😇 another super important bit is checking whether the user has a preference set in their OS for reduced motion. Some people have vestibular disorders and get mega quesy when looking at animations.

I pop this check at the start of all my animation functions, and return out if necessary.

const safeToAnimate = window.matchMedia('(prefers-reduced-motion: no-preference)')
.matches;

if (!safeToAnimate) return;

See the Pen Mouse movement demo by Cassie Evans (@cassie-codes) on CodePen.

What about Greensock?! permalink

Let’s see how we can do the same thing using Greensock! First we have to include the core library, if you’re on codepen, you can go to your pen settings and search for greensock.

pen settings on codepen

Now we’ve got the GSAP library in our pen, we can take advantage of gsap.ticker()

The greensock ticker is like the heartbeat of the GSAP engine – under the hood it uses requestAnimationFrame, just like we were using, but if that isn’t supported, the ticker automatically falls back to using a regular setTimeout() loop.

So rather than calling our function with request animation frame, we would do this…

function movePointer() {

}

gsap.ticker.add(movePointer);

Aside from making structuring animation itself more intuitive, Greensock provides a load of super cool utility functions that make your life easier. Remember all that work we did to get a nice usable range? Chuck that all in the bin. Look what we can do now!


let mapWidth;
let mapHeight;
function setMaps() {
mapWidth = gsap.utils.mapRange(0, innerWidth, -50, 50);
mapHeight = gsap.utils.mapRange(0, innerHeight, -50, 50);
}
window.addEventListener('resize', setMaps);
setMaps();

Now we can listen to the mouse movement, feed clientX and clientY into mapWidth, and we’ll get back a value within the range we’ve set!

let xPosition;
let yPosition;


function updateMouseCoords(event) {
xPosition = mapWidth(event.clientX);
yPosition = mapWidth(event.clientY);
}
window.addEventListener('mousemove', updateMouseCoords);

So tidy and concise!

Instead of updating CSS custom properties, we’re going to use a Greensock tween. A Tween is what does all the animation work, as I said at the start, it’s like a high-performance property manipulator.

A tween takes in two parameters

The targets, which are the object(s) whose properties you want to animate. Greensock uses document.querySelectorAll() internally so we can use any CSS selector we would use in CSS, or a direct reference to an element.

And the vars, an object containing all the properties/values you want to animate, along with any special properties like delay, ease, or duration.

function movePointer() {
gsap.to(pointer, {
xPercent: xPosition,
yPercent: yPosition,
ease: 'none'


});
}

gsap.ticker.add(movePointer);

I’ve added a couple more easing equations in here so you can change them out and see what a difference it can make to the movement.

See the Pen Mouse movement demo – GSAP – easing by Cassie Evans (@cassie-codes) on CodePen.

If you want to focus more on performance than easing you can use gsap.quickSetter to update the transforms. Creating a quickSetter function can boost performance around 50% – 250%!



const xSet = gsap.quickSetter(pointer, 'x', '%');
const ySet = gsap.quickSetter(pointer, 'y', '%');

function movePointer() {
xSet(xPosition);
ySet(yPosition);
}

gsap.ticker.add(movePointer);

See the Pen Mouse movement demo – GSAP by Cassie Evans (@cassie-codes) on CodePen.

Thanks for reading!

Next up – lets apply this to a SVG and fake some three dimensional movement!

(check back in for the next article in a couple of days!)

Got any questions about this article? Just pop me a message!





Source link

r/webdev - Keep getting Unexpected token < in JSON at position 0 error. Not sure what to do.
Strategy

Keep getting Unexpected token


Hello everyone, I have an ajax method that builds an html table with the data received from a php parser file. Whenever the button is pressed on the html, the method is triggered sending a request to the php file. For some reason, whenever the method is triggered, I keep receiving Unexpected token < in JSON at position 0 error in the console. What do you think could be the problem, even though the data sent back is formatted as JSON? Thanks a lot!

r/webdev - Keep getting Unexpected token < in JSON at position 0 error. Not sure what to do.

homeDataParser.php

r/webdev - Keep getting Unexpected token < in JSON at position 0 error. Not sure what to do.

home.html

P.S. Screens of the php and the html file is added to the post.



Source link

Screenshot of a Lighthouse audit showing a score of 100 out of 100.
Strategy

Make Jamstack Slow? Challenge Accepted.


“Jamstack is slowwwww.” That’s not something you hear often, right? Especially, when one of the main selling points of Jamstack is performance. But yeah, it’s true that even a Jamstack site can suffer hits to performance just like any other site. 

Don’t think that by choosing Jamstack you no longer have to think about performance. Jamstack can be fast — really fast — but you have to make the right choices. Let’s see if we can spot some of the poor decisions that can lead to a “slow” Jamstack site.

To do that, we’re going to build a really slow Gatsby site. Seems strange right? Why would we intentionally do that!? It’s the sort of thing where, if we make it, then perhaps we can gain a better understanding of what affects Jamstack performance and how to avoid bottlenecks.

We will use continuous performance testing and Google Lighthouse to audit every change. This will highlight the importance of testing every code change. Our site will start with a top Lighthouse performance score of 100. From there, we will make changes until it scores a mere 17. It is easier to do than you might think!

Let’s get started!

Creating our Jamstack site

We are going to use Gatsby for our test site. Let’s start by installing the Gatsby CLI installed:

npm install -g gatsby-cli

We can up a new Gatsby site using this command:

gatsby new slow-jamstack

Let’s cd into the new slow-jamstack project directory and start the development server:

cd slow-jamstack
gatsby develop

To add Lighthouse to the mix, we need a Gatsby production build. We can use Vercel to host the site, giving Lighthouse a way to runs its tests. That requires installing the Vercel command-line tool and logging in:

npm install -g vercel-cli
vercel

This will create the site in Vercel and put it on a live server. Here’s the example I’ve already set up that we’ll use for testing.

We’ve gotta use Chrome to access directly from DevTools and run a performance audit. No surprise here, the default Gatsby site is fast:

Screenshot of a Lighthouse audit showing a score of 100 out of 100.

A score of 100 is the fastest you can get. Let’s see what we can do to slow it down.

Slow CSS

CSS frameworks are great. They can do a lot of heavy lifting for you. When deciding on a CSS framework use one that is modular or employs CSS-in-JS so that the only CSS you need is what’s loaded.

But let’s make the bad decision to reach for an entire framework just to style a button component. In fact, let’s even grab the heaviest framework while we’re at it. These are the sizes of some popular frameworks:

Framework CSS Size (gzip)
Bootstrap 68kb (12kb)
Bulma 73kb (10kb)
Foundation 30kb (7kb)
Milligram 10kb (3kb)
Pure 17kb (4kb)
SemanticUI 146kb (20kb)
UIKit 33kb (6kb)

Alright, SemanticUI it is! The “right” way to load this framework would be to use a Sass or Less package, which would allow us to choose the parts of the framework we need. The wrong way would be to load all the CSS and JavaScript files in the <head> of the HTML. That’s what we’ll do with the full SemanticUI stylesheet. Plus, we’re going to link up jQuery because it’s a SemanticUI dependency.

We want these files to load in the head so let’s jump into the html.js file. This is not available in the src directory until we run a command to copy over the default from the cache:

cp .cache/default-html.js src/html.js

That gives us html.js in the src directory. Open it up and add the required stylesheet and scripts:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/semantic.css"></link>
<script src="https://code.jquery.com/jquery-3.1.1.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/semantic.js"></script>  

Now let’s push the changes straight to our production URL:

vercel --prod

OK, let’s view the audit…

Screenshot of a Lighthouse report showing a score of 66 out of 100.
Zoikes! A 33% reduction!

We have reduced the speed of the site down to a score of 66. Remember that we are not even using this framework at the moment. All we have done is load the files in the head and that reduced the performance score by one-third. Our Time to Interactive (TTI) jumped from a quick 1.9 seconds to a noticeable 4.9 seconds. And look at the possible savings we could get with from Lighthouse’s recommendations.

Slow marketing dependencies

Next, we are going to look at marketing tags and how these third-party scripts can affect performance. Let’s pretend we work with a marketing department and they want to start measuring traffic with Google Analytics. They also have a Facebook campaign and want to track it as well. 

They give us the details of the scripts that we need to add to get everything working. First, for Google Analytics:

<script async src="https://www.googletagmanager.com/gtag/js?id=UA-4369823-4"></script>
<script
  dangerouslySetInnerHTML={{ __html: `
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'UA-4369823-4');
  `}}
/>

Then for the Facebook campaign:

<script
  dangerouslySetInnerHTML={{ __html: `
    !function(f,b,e,v,n,t,s)
    {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
    n.callMethod.apply(n,arguments):n.queue.push(arguments)};
    if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
    n.queue=[];t=b.createElement(e);t.async=!0;
    t.src=v;s=b.getElementsByTagName(e)[0];
    s.parentNode.insertBefore(t,s)}(window, document,'script',
    'https://connect.facebook.net/en_US/fbevents.js');
    fbq('init', '3180830148641968');
    fbq('track', 'PageView');
    `}}
/>

<noscript><img height="1" width="1" src="https://www.facebook.com/tr?id=3180830148641968&ev=PageView&noscript=1"/></noscript>

We’ll place these scripts inside html.js, again in the <head> section, before the closing </head> tag.

Just like before, let’s push to Vercel and re-run Lighthouse:

vercel --prod
Screenshot of a Lighthouse audit showing a score of 51 out of 100.

Wow, the site is already down to 51 and all we’ve done is tack on one framework and a couple of measly scripts. Together, they/ve reduced the score by a whopping 49 points, nearly half of where we started.

Slow images

We haven’t added any images to the site yet but we know we absolutely would in a real-life scenario. We are going to add 100 images to the page. Sure, 100 is a lot for a single page but, then again, we know that images are often the biggest culprits of bloated web pages so we might as well let them shine.

We’ll make things a little worse by hot loading the images directly from https://placeimg.com instead of serving them on our own server.

Let’s crack open index.js and drop this code in, which will loop through 100 instances of images:

const IndexPage = () => {
  const items = []
  for(var i = 0; i < 100; i++) {
    const url = `http://placeimg.com/640/360/any?=${i}`
    items.push(<img key={i} alt={i} src={url} />)
  }
  
  return (
    <Layout>
      // ...
      {items}
      // ...
    </Layout>
  )
}

The 100 images are all different and will all load as the page loads, thereby blocking the rendering. OK, let’s push to Vercel and see what’s up.

vercel --prod
Screenshot of a Lighthouse audit showing a score of 17 out of 100.
That score deserves a sad trombone. 🎺

OK, we now have a very slow Jamstack site. The images are blocking the rendering of the page and the TTI is now a whopping 16.5 seconds. We have taken a very fast Jamstack site and dropped it to a Lighthouse score of 17 — a reduction of 83 points!

Now, you may be think that you would never make these poor decisions when building an app. But you are missing the point. Every choice we make has an impact on performance. It’s a balance and performance does not come free. Even on Jamstack sites.

Making Jamstack fast again

You have seen that we cannot ignore client-side performance when using Jamstack. 

So why do people say that Jamstack is fast? Well, the main advantage of Jamstack — or using static site generators in general — is caching. Static files are cached on the edge reducing Time to First Byte (TTFB).

This is always going to be faster than going to a single-origin web server before generating the page. This is a great feature of Jamstack and gives you a fighting chance to create a page that can hit 100 in Lighthouse. (But, hey, as a side note, remember that great scores aren’t always indicative of an actual user experience.)


See, I told you we could make Jamstack slow! There are also many other things that can slow it down, but hopefully this drives home the point.

While we’re talking about performance, here are a few of my favorite performance articles on here at CSS-Tricks:



Source link

r/graphic_design - Rebranding - JM Logo
Strategy

Rebranding – JM Logo : graphic_design


Good day! I am in the means of rebranding myself as a graphic designer, especially as my previous design has been referenced as an Adidas rip off lol.

I have had this design for some time, and this comment, and the extra free time, has allowed me to change up my design into something a bit more playful. Please see my new logo design with a quick branding solution for a background. There is a subtle nod to my home country in the design as well.

I would love any feedback on how to better my new design. I am not convinced of the colouring but wanted to create something more modern and diverse.

r/graphic_design - Rebranding - JM Logo



Source link