What Hooks Mean for Vue

Not to be confused with Lifecycle Hooks, Hooks were introduced in React in v16.7.0-alpha, and a proof of concept was released for Vue a few days after. Even though it was proposed by React, it’s actually an important composition mechanism that has benefits across JavaScript framework ecosystems, so we’ll spend a little time today discussing what this means.

Mainly, Hooks offer a more explicit way to think of reusable patterns — one that avoids rewrites to the components themselves and allows disparate pieces of the stateful logic to seamlessly work together.

The initial problem

In terms of React, the problem was this: classes were the most common form of components when expressing the concept of state. Stateless functional components were also quite popular, but due to the fact that they could only really render, their use was limited to presentational tasks.

Classes in and of themselves present some issues. For example, as React became more ubiquitous, stumbling blocks for newcomers did as well. In order to understand React, one had to understand classes, too. Binding made code verbose and thus less legible, and an understanding of this in JavaScript was required. There are also some optimization stumbling blocks that classes present, discussed here.

In terms of the reuse of logic, it was common to use patterns like render props and higher-order components, but we’d find ourselves in similar “pyramid of doom” — style implementation hell where nesting became so heavily over-utilized that components could be difficult to maintain. This led me to ranting drunkenly at Dan Abramov, and nobody wants that.

Hooks address these concerns by allowing us to define a component’s stateful logic using only function calls. These function calls become more compose-able, reusable, and allows us to express composition in functions while still accessing and maintaining state. When hooks were announced in React, people were excited — you can see some of the benefits illustrated here, with regards to how they reduce code and repetition:

In terms of maintenance, simplicity is key, and Hooks provide a single, functional way of approaching shared logic with the potential for a smaller amount of code.

Why Hooks in Vue?

You may read through this and wonder what Hooks have to offer in Vue. It seems like a problem that doesn’t need solving. After all, Vue doesn’t predominantly use classes. Vue offers stateless functional components (should you need them), but why would we need to carry state in a functional component? We have mixins for composition where we can reuse the same logic for multiple components. Problem solved.

I thought the same thing, but after talking to Evan You, he pointed out a major use case I missed: mixins can’t consume and use state from one to another, but Hooks can. This means that if we need chain encapsulated logic, it’s now possible with Hooks.

Hooks achieve what mixins do, but avoid two main problems that come with mixins:

  • They allows us to pass state from one to the other.
  • They make it explicit where logic is coming from.

If we’re using more than one mixin, it’s not clear which property was provided by which mixin. With Hooks, the return value of the function documents the value being consumed.

So, how does that work in Vue? We mentioned before that, when working with Hooks, logic is expressed in function calls that become reusable. In Vue, this means that we can group a data call, a method call, or a computed call into another custom function, and make them freely compose-able. Data, methods, and computed now become available in functional components.

Example

Let’s go over a really simple hook so that we can understand the building blocks before we move on to an example of composition in Hooks.

useWat?

OK, here’s were we have, what you might call, a crossover event between React and Vue. The use prefix is a React convention, so if you look up Hooks in React, you’ll find things like useState, useEffect, etc. More info here.

In Evan’s live demo, you can see where he’s accessing useState and useEffect for a render function.

If you’re not familiar with render functions in Vue, it might be helpful to take a peek at that.

But when we’re working with Vue-style Hooks, we’ll have — you guessed it — things like: useData, useComputed, etc.

So, in order for us look at how we’d use Hooks in Vue, I created a sample app for us to explore.

In the src/hooks folder, I’ve created a hook that prevents scrolling on a useMounted hook and reenables it on useDestroyed. This helps me pause the page when we’re opening a dialog to view content, and allows scrolling again when we’re done viewing the dialog. This is good functionality to abstract because it would probably be useful several times throughout an application.

import { useDestroyed, useMounted } from "vue-hooks"; export function preventscroll() { const preventDefault = (e) => { e = e || window.event; if (e.preventDefault) e.preventDefault(); e.returnValue = false; } // keycodes for left, up, right, down const keys = { 37: 1, 38: 1, 39: 1, 40: 1 }; const preventDefaultForScrollKeys = (e) => { if (keys[e.keyCode]) { preventDefault(e); return false; } } useMounted(() => { if (window.addEventListener) // older FF window.addEventListener('DOMMouseScroll', preventDefault, false); window.onwheel = preventDefault; // modern standard window.onmousewheel = document.onmousewheel = preventDefault; // older browsers, IE window.touchmove = preventDefault; // mobile window.touchstart = preventDefault; // mobile document.onkeydown = preventDefaultForScrollKeys; }); useDestroyed(() => { if (window.removeEventListener) window.removeEventListener('DOMMouseScroll', preventDefault, false); //firefox window.addEventListener('DOMMouseScroll', (e) => { e.stopPropagation(); }, true); window.onmousewheel = document.onmousewheel = null; window.onwheel = null; window.touchmove = null; window.touchstart = null; document.onkeydown = null; });
} 

And then we can call it in a Vue component like this, in AppDetails.vue:

<script>
import { preventscroll } from "./../hooks/preventscroll.js";
... export default { ... hooks() { preventscroll(); }
}
</script>

We’re using it in that component, but now we can use the same functionality throughout the application!

Two Hooks, understanding each other

We mentioned before that one of the primary differences between hooks and mixins is that hooks can actually pass values from one to another. Let’s look at that with a simple, albeit slightly contrived, example.

Let’s say in our application we need to do calculations in one hook that will be reused elsewhere, and something else that needs to use that calculation. In our example, we have a hook that takes the window width and passes it into an animation to let it know to only fire when we’re on larger screens.

In the first hook:

import { useData, useMounted } from 'vue-hooks'; export function windowwidth() { const data = useData({ width: 0 }) useMounted(() => { data.width = window.innerWidth }) // this is something we can consume with the other hook return { data }
}

Then, in the second we use this to create a conditional that fires the animation logic:

// the data comes from the other hook
export function logolettering(data) { useMounted(function () { // this is the width that we stored in data from the previous hook if (data.data.width > 1200) { // we can use refs if they are called in the useMounted hook const logoname = this.$refs.logoname; Splitting({ target: logoname, by: "chars" }); TweenMax.staggerFromTo(".char", 5, { opacity: 0, transformOrigin: "50% 50% -30px", cycle: { color: ["red", "purple", "teal"], rotationY(i) { return i * 50 } } }, ...

Then, in the component itself, we’ll pass one into the other:

<script>
import { logolettering } from "./../hooks/logolettering.js";
import { windowwidth } from "./../hooks/windowwidth.js"; export default { hooks() { logolettering(windowwidth()); }
};
</script>

Now we can compose logic with Hooks throughout our application! Again, this is a contrived example for the purposes of demonstration, but you can see how useful this might be for large scale applications to keep things in smaller, reusable functions.

Future plans

Vue Hooks are already available to use today with Vue 2.x, but are still experimental. We’re planning on integrating Hooks into Vue 3, but will likely deviate from React’s API in our own implementation. We find React Hooks to be very inspiring and are thinking about how to introduce its benefits to Vue developers. We want to do it in a way that complements Vue’s idiomatic usage, so there’s still a lot of experimentation to do.

You can get started by checking out the repo here. Hooks will likely become a replacement for mixins, so although the feature still in its early stages, it’s probably a concept that would be beneficial to explore in the meantime.

(Sincere thanks to Evan You and Dan Abramov for proofing this article.)

The post What Hooks Mean for Vue appeared first on CSS-Tricks.

More Like position: tricky;

I rather like position: sticky;. It has practical use cases. I think of things like keeping a table of contents in a sidebar of a long article, but as a fairly simple implementation and without risk of overlapping things in awkward ways. But Elad Shechter is right here: it’s not used that much — at least partially — and probably because it’s a bit weird to understand.

I like how Elad explains it with a “Sticky Item” and a “Sticky Container.” The container needs to be large enough that scrolling is relevant and for the stickiness to do anything at all.

There are other gotchas, too. I feel like every time I try position: sticky; in a real context, I have about a 30% chance of it working. There always seems to be some parent/child relationship thing that I can’t quite work out to prevent overlaps. Or, there is some parent element with overflow: hidden;, which, for reasons unbeknownst to me, breaks this.

Direct Link to ArticlePermalink

The post More Like position: tricky; appeared first on CSS-Tricks.

React’s Experimental Suspense API Will Rock for Fallback UI During Data Fetches

Most web applications built today receive data from an API. When fetching that data, we have to take certain situations into consideration where the data might not have been received. Perhaps it was a lost connection. Maybe it was the endpoint was changed. Who knows. Whatever the issue, it’s the end user who winds up with a big bag of nothing on the front end.

So we ought to account for that!

The common way of handling this is to have something like an isLoading state in the app. The value of isLoading is dependent on the data we want to receive. For example, it could be a simple boolean where a returned true (meaning we’re still waiting on the data), we display a loading spinner to indicate that the app is churning. Otherwise, wee’ll show the data.

Oh god, no!
📷 Credit: Jian Wei

While this isn‘t entirely bad, the awesome folks working on React have implemented (and are continuing to work on) a baked-in solution to handle this using a feature called Suspense.

Suspense sorta does what its name implies

You may have guessed it from the name, but Suspense tells a component to hold off from rendering until a condition has been met. Just like we discussed with isLoading, the rendering of the data is postponed until the API fetches the data and isLoading is set to false. Think of it like a component is standing in an elevator waiting for the right floor before stepping out.

At the moment, Suspense can only be used to conditionally load components that use React.lazy() to render dynamically, without a page reload. So, say we have a map that takes a bit of time to load when the user selects a location. We can wrap that map component with Suspense and call something like the Apple beachball of death to display while we’re waiting on the map. then, once the map loads, we kick the ball away.

// Import the Map component
const Map = React.lazy(() => import('./Map')); function AwesomeComponent() [ return ( // Show the <Beachball> component until the <Map> is ready <React.Suspense fallback={<Beachball />}> <div> <Map /> </div> </React.Suspense> );
}

Right on. Pretty straightforward so far, I hope.

But what if we want the fallback beachball, not for a component that has loaded, but when waiting for data to be returned from an API. Well, that’s a situation Suspense seems perfectly suited for, but unfortunately, does not handle that quite yet. But it will.

In the meantime, we can put an experimental feature called react-cache (the package previously known as simple-cache-provider) to demonstrate how Suspense ought to work with API fetching down the road.

Let’s use Suspense with API data anyway

OK, enough suspense (sorry, couldn‘t resist). Let’s get to a working example where we define and display a component as a fallback while we’re waiting for an API to spit data back at us.

Remember, react-cache is experimental. When I say experimental, I mean just that. Even the package description urges us to refrain from using it in production.

Here’s what we’re going to build: a list of users fetched from an API.

Get Source Code

Alright, let’s begin!

First, spin up a new project

Let’s start by generating a new React application using create-react-app.

## Could be any project name
create-react-app csstricks-react-suspense

This will bootstrap your React application. Because the Suspense API is still a work in progress, we will make use of a different React version. Open the package.json file in the project’s root directory, edit the React and React-DOM version numbers, and add the simple-cache-provider package (we’ll look into that later). Here’s what that looks like:

"dependencies": { "react": "16.4.0-alpha.0911da3", "react-dom": "16.4.0-alpha.0911da3", "simple-cache-provider": "0.3.0-alpha.0911da3"
}

Install the packages by running yarn install.

In this tutorial, we will build the functionality to fetch data from an API. We can use the createResource() function from simple-cache-provider to do that in the src/fetcher.js file:

import { createResource } from 'simple-cache-provider'; const sleep = (duration) => { return new Promise((resolve) => { setTimeout(() => { resolve() }, duration) })
} const loadProfiles = createResource(async () => { await sleep(3000) const res = await fetch(`https://randomuser.me/api/?results=15`); return await res.json();
}); export default loadProfiles

So, here’s what’s happening there. The sleep() function blocks the execution context for a specific duration, which will be passed as an argument. The sleep() function is then called in the loadProfiles() function to stimulate a delay of three seconds (3,000ms). By using createResource() to make the API call, we either return the resolved value (which is the data we are expecting from the API) or throw a promise.

Next, we will create a higher-order component called withCache that enable caching on the component it wraps. We’ll do that in a new file called, creatively, withCache.js. Go ahead and place that in the project’s src directory.

import React from 'react';
import { SimpleCache } from 'simple-cache-provider'; const withCache = (Component) => { return props => ( <SimpleCache.Consumer> {cache => <Component cache={cache} {...props} />} </SimpleCache.Consumer> );
} export default withCache;

This higher-order component uses SimpleCache from the simple-cache-provider package to enable the caching of a wrapped component. We’ll make use of this when we create our next component, I promise. In the meantime, create another new file in src called Profile.js — this is where we’ll map through the results we get from the API.

import React, { Fragment } from 'react';
import loadProfiles from './fetcher'
import withCache from './withCache' // Just a little styling
const cardWidth = { width: '20rem'
} const Profile = withCache((props) => { const data = loadProfiles(props.cache); return ( <Fragment> { data.results.map(item => ( <div key={item.login.uuid} className="card" style={cardWidth}> <div> <img src={item.picture.thumbnail} /> </div> <p>{item.email}</p> </div> )) } </Fragment> )
}); export default Profile

What we have here is a Profile component that’s wrapped in withCache the higher-order component we created earlier. Now, whatever we get back from the API (which is the resolved promise) is saved as a value to the data variable, which we’ve defined as the props for the profile data that will be passed to the components with cache (props.cache).

To handle the loading state of the app before the data is returned from the API, we’ll implement a placeholder component which will render before the API responds with the data we want.

Here’s what we want the placeholder to do: render a fallback UI (which can be a loading spinner, beach ball or what have you) before the API responds, and when the API responds, show the data. We also want to implement a delay (delayMs ) which will come in handy for scenarios where there’s almost no need to show the loading spinner. For example; if the data comes back in less than two seconds, then maybe a loader is a bit silly.

The placeholder component will look like this;

const Placeholder = ({ delayMs, fallback, children }) => { return ( <Timeout ms={delayMs}> {didTimeout => { return didTimeout ? fallback : children; }} </Timeout> );
}

delayMs, fallback and children will be passed to the Placeholder component from the App component which we will see shortly. The Timeout component returns a boolean value which we can use to either return the fallback UI or the children of the Placeholder component (the Profile component in this case).

Here’s the final markup of our App, piecing together all of the components we’ve covered, plus some decorative markup from Bootstrap to create a full page layout.

class App extends React.Component { render() { return ( <React.Fragment> // Bootstrap Containers and Jumbotron <div className="App container-fluid"> <div className="jumbotron"> <h1>CSS-Tricks React Suspense</h1> </div> <div className="container"> <div> // Placeholder contains Suspense and wraps what needs the fallback UI <Placeholder delayMs={1000} fallback={ <div className="row"> <div className="col-md"> <div className="div__loading"> <Loader /> </div> </div> </div> } > <div className="row"> // This is what will render once the data loads <Profile /> </div> </Placeholder> </div> </div> </div> </React.Fragment> ); }
}

That’s a wrap

Pretty neat, right? It’s great that we’re in the process of getting true fallback UI support right out of the React box, without crafty tricks or extra libraries. Totally makes sense given that React is designed to manage states and loading being a common state to handle.

Remember, as awesome as Suspense is (and it is really awesome), it is important to note that it’s still in experimental phase, making it impractical in a production application. But, since there are ways to put it to use today, we can still play around with it in a development environment all we want, so experiment away!

Folks who have been working on and with Suspense have been writing up their thoughts and experience. Here are a few worth checking out:

The post React’s Experimental Suspense API Will Rock for Fallback UI During Data Fetches appeared first on CSS-Tricks.

Well, Typetura seems fun

I came across this update from Scott Kellum’s and Sal Hernandez’s project Typetura via my Medium feed this morning, and what a delight?!

(Also, wow, I really have been out of the game for a minute.)

This is quite exciting! Typetura wants to deal with some of the main problems that come up when utilizing fluid type in your CSS.

Typetura was created to make fluid typography mainstream. To do this there were two problems to solve. First, develop an implementation that is feature rich and easy to implement with CSS. Second, create a design tool that designers can use to illustrate how they want fluid typography to look.

I love a tool that tries to remove friction and make technologies easier to use.

To ensure the implementation was easy to use and understand, Typetura needed a simple, declarative syntax in vanilla CSS. This means no complicated math or Sass tricks.

Design software is constructed around fixed art boards, but there needs to be a way for designers to communicate how designs transition between sizes… Typetura is a tool that enables designers to work with a fluid canvas.

Direct Link to ArticlePermalink

The post Well, Typetura seems fun appeared first on CSS-Tricks.

How do you figure?

Scott O’Hara digs into the <figure> and <figcaption> elements. Gotta love a good ol’ HTML deep dive.

I use these on just about every blog post here on CSS-Tricks, and as I’ve suspected, I’ve basically been doing it wrong forever. My original thinking was that a figcaption was just as good as the alt attribute. I generally use it to describe the image.

<figure> <img src="starry-night.jpg" alt=""> <figcaption>The Starry Night, a famous painting by Vincent van Gogh</figcaption>
</figure>

I intentionally left off the alt text, because the figcaption is saying what I would want to say in the alt text and I thought duplicating it would be annoying (to a screen reader user) and unnecessary. Scott says that’s bad as the empty alt text makes the image entirely undiscoverable by some screen readers and the figure is describing nothing as a result.

The correct answer, I think, is to do more work:

<figure> <img src="starry-night.jpg" alt="An abstract painting with a weird squiggly tree thing in front of a swirling starry nighttime sky."> <figcaption>The Starry Night, a famous painting by Vincent van Gogh</figcaption>
</figure>

It’s a good goal, and I should do better about this. It’s just laziness that gets in the way, and laziness that makes me wish there was a pattern that allowed me to write a description once that worked for both. Maybe something like Nino Ross Rodriguez just shared today where artificial intelligence can take some of the lift. But that’s kinda not the point here. The point is that you can’t write it once because <figcaption> and alt do different things.

Direct Link to ArticlePermalink

The post How do you figure? appeared first on CSS-Tricks.

Using Artificial Intelligence to Generate Alt Text on Images

Web developers and content editors alike often forget or ignore one of the most important parts of making a website accessible and SEO performant: image alt​ text. You know, that seemingly small image attribute that describes an image:

​​​<img src="/cute/sloth/image.jpg" alt="A brown baby sloth staring straight into the camera with a tongue sticking out." >

A brown baby sloth staring straight into the camera with a tongue sticking out.
📷 Credit: Huffington Post

If you regularly publish content on the web, then you know it can be tedious trying to come up with descriptive text. Sure, 5-10 images is doable. But what if we are talking about hundreds or thousands of images? Do you have the resources for that?

Let’s look at some possibilities for automatically generating alt text for images with the use of computer vision and image recognition services from the likes Google, IBM, and Microsoft. They have the resources!

Reminder: What is alt text good for?

Often overlooked during web development and content entry, the alt​ attribute is a small bit of HTML code that describes an image that appears on a page. It’s so inconspicuous that it may not appear to have any impact on the average user, but it has very important uses indeed:

  • ​​Web Accessibility for Screen Readers: Imagine a page with lots of images and not a single one contains alt​ text. A user surfing in using a screen reader would only hear the word “image” blurted out and that’s not very helpful. Great, there’s an image, but what is it? Including alt​ enables screen readers to help the visually impaired “see” what’s there and have a better understanding of the content of the page. They say a picture is worth a thousand words — that’s a thousand words of context a user could be missing.
  • Display text if an image does not load: The World Wide Web seems infallible and, like New York City, that it never sleeps, but flaky and faulty connections are a real thing and, if that happens, well, images tend not to load properly and “break.” Alt text is a safeguard in that it displays on the page in place of where the “broken” image is, providing users with content as a fallback.
  • ​​SEO performance: Alt text on images contributes to SEO performance as well. Though it doesn’t exactly help a site or page skyrocket to the top of the search results, it is one factor to keep in mind for SEO performance.

Knowing how important these things are, hopefully you’ll be able to include proper alt​ text during development and content entry. But are your archives in good shape? Trying to come up with a detailed description for a large backlog of images can be a daunting task, especially if you’re working on tight deadlines or have to squeeze it in between other projects.

What if there was a way to apply alt​ text as an image is uploaded? And! What if there was a way to check the page for missing alt​ tags and automagically fill them in for us?

There are available solutions!

Computer vision (or image recognition) has actually been offered for quite some time now. Companies like Google, IBM and Microsoft have their own APIs publicly available so that developers can tap into those capabilities and use them to identify images as well as the content in them.

There are developers who have already utilized these services and created their own plugins to generate alt​ text. Take Sarah Drasner’s generator, for example, which demonstrates how Azure’s Computer Vision API can be used to create alt​ text for any image via upload or URL. Pretty awesome!

​​See the Pen
​​Dynamically Generated Alt Text with Azure's Computer Vision API
by Sarah Drasner (@sdras)
​​on CodePen.
​​

There’s also Automatic Alternative Text by Jacob Peattie, which is a WordPress plugin that uses the same Computer Vision API. It’s basically an addition to the workflow that allows the user to upload an image and generated alt​ text automatically.

​​Tools like these generally help speed-up the process of content management, editing and maintenance. Even the effort of thinking of a descriptive text has been minimized and passed to the machine!

Getting Your Hands Dirty With AI

I have managed to have played around with a few AI services and am confident in saying that Microsoft Azure’s Computer Vision produces the best results. The services offered by Google and IBM certainly have their perks and can still identify images and proper results, but Microsoft’s is so good and so accurate that it’s not worth settling for something else, at least in my opinion.

Creating your own image recognition plugin is pretty straightforward. First, head down to Microsoft Azure Computer Vision. You’ll need to login or create an account in order to grab an API key for the plugin.

Once you’re on the dashboard, search and select Computer Vision and fill in the necessary details.

Starting out

Wait for the platform to finish spinning up an instance of your computer vision. The API keys for development will be available once it’s done.

​​Keys: Also known as the Subscription Key in the official documentation

Let the interesting and tricky parts begin! I will be using vanilla JavaScript for the sake of demonstration. For other languages, you can check out the documentation. Below is a straight-up copy and paste of the code and you can use to replace the placeholders.

​​var request = new XMLHttpRequest();
request.open('POST', 'https://[LOCATION]/vision/v1.0/describe?maxCandidates=1&language=en', true);
request.setRequestHeader('Content-Type', 'application/json');
request.setRequestHeader('Ocp-Apim-Subscription-Key', '[SUBSCRIPTION_KEY]');
request.send(JSON.stringify({ "url": "[IMAGE_URL]" }));
request.onload = function () { var resp = request.responseText; if (request.status >= 200 && request.status < 400) { // Success! console.log('Success!'); } else { // We reached our target server, but it returned an error console.error('Error!'); } console.log(JSON.parse(resp));
}; request.onerror = function (e) { console.log(e);
};

Alright, let’s run through some key terminology of the AI service.

  • Location: This is the subscription location of the service that was selected prior to getting the subscription keys. If you can’t remember the location for some reason, you can go to the Overview screen and find it under Endpoint.
  • ​​

Overview > Endpoint : To get the location value
  • ​​Subscription Key: This is the key that unlocks the service for our plugin use and can be obtained under Keys. There’s two of them, but it doesn’t really matter which one is used.
  • ​​Image URL: This is the path for the image that’s getting the alt​ text. Take note that the images that are sent to the API must meet specific requirements:
    • File type must be JPEG, PNG, GIF, BMP
    • ​File size must be less than 4MB
    • ​​Dimensions should be greater than 50px by 50px

Easy peasy

​​Thanks to big companies opening their services and API to developers, it’s now relatively easy for anyone to utilize computer vision. As a simple demonstration, I uploaded the image below to Microsoft Azure’s Computer Vision API.

Possible alt​ text: a hand holding a cellphone

​​The service returned the following details:

​​{ "description": { "tags": [ "person", "holding", "cellphone", "phone", "hand", "screen", "looking", "camera", "small", "held", "someone", "man", "using", "orange", "display", "blue" ], "captions": [ { "text": "a hand holding a cellphone", "confidence": 0.9583763512737793 } ] }, "requestId": "31084ce4-94fe-4776-bb31-448d9b83c730", "metadata": { "width": 920, "height": 613, "format": "Jpeg" }
}

​​From there, you could pick out the alt​ text that could be potentially used for an image. How you build upon this capability is your business:

  • ​​You could create a CMS plugin and add it to the content workflow, where the alt​ text is generated when an image is uploaded and saved in the CMS.
  • ​​You could write a JavaScript plugin that adds alt​ text on-the-fly, after an image has been loaded with notably missing alt​ text.
  • ​​You could author a browser extension that adds alt​ text to images on any website when it finds images with it missing.
  • ​​You could write code that scours your existing database or repo of content for any missing alt​ text and updates them or opens pull requests for suggested changes.

​​Take note that these services are not 100% accurate. They do sometimes return a low confidence rating and a description that is not at all aligned with the subject matter. But, these platforms are constantly learning and improving. After all, Rome wasn’t built in a day.

The post Using Artificial Intelligence to Generate Alt Text on Images appeared first on CSS-Tricks.

The Many Ways to Change an SVG Fill on Hover (and When to Use Them)

SVG is a great format for icons. Vector formats look crisp and razor sharp, no matter the size or device — and we get tons of design control when using them inline.

SVG also gives us another powerful feature: the ability to manipulate their properties with CSS. As a result, we can make quick and simple interactions where it used to take crafty CSS tricks or swapping out entire image files.

Those interactions include changing color on hover states. It sounds like such a straightforward thing here in 2019, but there are actually a few totally valid ways to go about it — which only demonstrates the awesome powers of SVG more.

First off, let’s begin with a little abbreviated SVG markup:

<svg class="icon"> <path .../>
</svg>

Target the .icon class in CSS and set the SVG fill property on the hover state to swap colors.

.icon:hover { fill: #DA4567;
}

This is by far the easiest way to apply a colored hover state to an SVG. Three lines of code!

SVGs can also be referenced using an <img> tag or as a background image. This allows the images to be cached and we can avoid bloating your HTML with chunks of SVG code. But the downside is a big one: we no longer have the ability to manipulate those properties using CSS. Whenever I come across non-inline icons, my first port of call is to inline them, but sometimes that’s not an option.

I was recently working on a project where the social icons were a component in a pattern library that everyone was happy with. In this case, the icons were being referenced from an <img> element. I was tasked with applying colored :focus and :hover styles, without adjusting the markup.

So, how do you go about adding a colored hover effect to an icon if it’s not an inline SVG?

CSS Filters

CSS filters allow us to apply a whole bunch of cool, Photoshop-esque effects right in the browser. Filters are applied to the element after the browser renders layout and initial paint, which means they fall back gracefully. They apply to the whole element, including children. Think of a filter as a lens laid over the top of the element it’s applied to.

These are the CSS filters available to us:

  • brightness(<number-percentage>);
  • contrast(<number-percentage>);
  • grayscale(<number-percentage>);
  • invert(<number-percentage>);
  • opacity(<number-percentage>);
  • saturate(<number-percentage>);
  • sepia(<number-percentage>);
  • hue-rotate(<angle>);
  • blur(<length>);
  • drop-shadow(<length><color>);

All filters take a value which can be changed to adjust the effect. In most cases, this value can be expressed in either a decimal or percent units (e.g. brightness(0.5) or brightness(50%)).

Straight out of the box, there’s no CSS filter that allows us to add our own specific color.
We have hue-rotate(), but that only adjusts an existing color; it doesn’t add a color, which is no good since we’re starting with a monochromatic icon.

The game-changing bit about CSS filters is that we don’t have to use them in isolation. Multiple filters can be applied to an element by space-separating the filter functions like this:

.icon:hover { filter: grayscale(100%) sepia(100%);
}

If one of the filter functions doesn’t exist, or has an incorrect value, the whole list is ignored and no filter will be applied to the element.

When applying multiple filter functions to an element, their order is important and will affect the final output. Each filter function will be applied to the result of the previous operation.

So, in order to colorize our icons, we have to find the right combination.

To make use of hue-rotate(), we need to start off with a colored icon. The sepia() filter is the only filter function that allows us to add a color, giving the filtered element a yellow-brown-y tinge, like an old photo.

The output color is dependent on the starting tonal value:

In order to add enough color with sepia(), we first need to use invert() to convert our icon to a medium grey:

.icon:hover { filter: invert(0.5)
}

We can then add the yellow/brown tone with sepia():

.icon:hover { filter: invert(0.5) sepia(1);
}

…then change the hue with hue-rotate():

.icon:hover { filter: invert(0.5) sepia(1) hue-rotate(200deg); }

Once we have the rough color we want, we can tweak it with saturation() and brightness():

.icon:hover { filter: invert(0.5) sepia(1) hue-rotate(200deg) saturate(4) brightness(1);
}

I’ve made a little tool for this to make your life a little easier, as this is a pretty confusing process to guesstimate.

See the Pen CSS filter example by Cassie Evans (@cassie-codes)
on CodePen.

Even with the tool, it’s still a little fiddly, not supported by Internet Explorer, and most importantly, you’re unable to specify a precise color.

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

Chrome Opera Firefox IE Edge Safari
18* 15* 35 No 18 6*

Mobile / Tablet

iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
6.0-6.1* 46 No 4.4* 71 64

So, what do we do if we need a specific hex code?

SVG Filters

If we need more precise control (and better browser support) than CSS filters can offer, then it’s time to turn to SVG.

Filters originally came from SVG. In fact, under the hood, CSS filters are just shortcuts to SVG filters with a particular set of values baked in.

Unlike CSS, the filter isn’t predefined for us, so we have to create it. How do we do this?

This is the syntax to define a filter:

<svg xmlns="<http://www.w3.org/2000/svg>" version="1.1"> <defs> <filter id="id-of-your-filter"> ...  ... </filter> ... </defs>
</svg>

Filters are defined by a <filter> element, which goes inside the <defs> section of an SVG.

SVG filters can be applied to SVG content within the same SVG document. Or, the filter can be referenced and applied to HTML content elsewhere.

To apply an SVG filter to HTML content, we reference it the same way as a CSS filter: by using the url() filter function. The URL points to the ID of the SVG filter.

.icon:hover { filter: url('#id-of-your-filter');
}

The SVG filter can be placed inline in the document or the filter function can reference an external SVG. I prefer the latter route as it allows me to keep my SVG filters tidied away in an assets folder.

.icon:hover { filter: url('assets/your-SVG.svg#id-of-your-filter');
}

Back to the <filter> element itself.

<filter id="id-of-your-filter"> ...  ...
</filter>

Right now, this filter is empty and won’t do anything as we haven’t defined a filter primitive. Filter primitives are what create the filter effects. There are a number of filter primitives available to us, including:

  • [<feBlend>]
  • [<feColorMatrix>]
  • [<feComponentTransfer>]
  • [<feComposite>]
  • [<feConvolveMatrix>]
  • [<feDiffuseLighting>]
  • [<feDisplacementMap>]
  • [<feDropShadow>]
  • [<feFlood>]
  • [<feGaussianBlur>]
  • [<feImage>]
  • [<feMerge>]
  • [<feMorphology>]
  • [<feOffset>]
  • [<feSpecularLighting>]
  • [<feTile>]
  • [<feTurbulence>]

Just like with CSS filters, we can use them on their own or include multiple filter primitives in the <filter> tag for more interesting effects. If more than one filter primitive is used, then each operation will build on top of the previous one.

For our purposes we’re just going to use feColorMatrix, but if you want to know more about SVG filters, you can check out the specs on MDN or this (in progress, at the time of this writing) article series that Sara Soueidan has kicked off.

feColourMatrix allows us to change color values on a per-channel basis, much like channel mixing in Photoshop.

This is what the syntax looks like:

<svg xmlns="<http://www.w3.org/2000/svg>" version="1.1"> <defs> <filter id="id-of-your-filter"> <feColorMatrix color-interpolation-filters="sRGB" type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "/> </filter> ... </defs>
</svg>

The color-interpolation-filters attribute specifies our color space. The default color space for filter effects is linearRGB, whereas in CSS, RGB colors are specified in the sRGB color space. It’s important that we set the value to sRGB in order for our colors to match up.

Let’s have a closer look at the color matrix values.

The first four columns represent the red, green and blue channels of color and the alpha (opacity) value. The rows contain the red, green, blue and alpha values in those channels.

The M column is a multiplier — we don’t need to change any of these values for our purposes here. The values for each color channel are represented as floating point numbers in the range 0 to 1.

We could write these values as a CSS RGBA color declaration like this:

rgba(255, 255, 255, 1)

The values for each color channel (red, green and blue) are stored as integers in the range 0 to 255. In computers, this is the range that one 8-bit byte can offer.

By dividing these color channel values by 255, the values can be represented as a floating point number which we can use in the feColorMatrix.

And, by doing this, we can create a color filter for any color with an RGB value!

Like teal, for example:

rgba(0, 128, 128, 1). 128%255=0.50

See the Pen
SVG filter – teal hover
by Cassie Evans (@cassie-codes)
on CodePen.

This SVG filter will only impart color to icons with a white fill, so If we have an icon with a black fill, we can use invert() to convert it to white before applying the SVG filter.

.icon:hover { filter: invert(100%) url('assets/your-SVG.svg#id-of-your-filter');
}

If we just have a hex code, the math is a little trickier, although there are plenty of hex-to-RGBA converters out there. To help out, I’ve made a HEX to feColorMatrix converter.

See the Pen
HEX to feColorMatrix converterr
by Cassie Evans (@cassie-codes)
on CodePen.

Have a play around, and happy filtering!

The post The Many Ways to Change an SVG Fill on Hover (and When to Use Them) appeared first on CSS-Tricks.

Forms that Move With You with Wufoo

I’ve been into the idea of JAMstack lately. In fact, it was at the inaugural JAMstack_conf that I gave a talked called The All-Powerful Font-End Developer. My overall point there was that there are all these services that we can leverage as front-end developers to build complete websites without needing much help from other disciplines — if any at all.

Sometimes, the services we reach for these days are modern and fancy, like a real-time database solution with authentication capabilities. And sometimes those services help process forms. Speaking of which, a big thanks to Wufoo for so successfully being there for us front-end developers for so many years. Wufoo was one of my first tastes of being a powerful front-end developer. I can build and design a complex form super fast on Wufoo and integrate it onto any site in minutes. I’ve done it literally hundreds of times, including here on CSS-Tricks.

Another thing that I love about building Wufoo forms is that they travel so well. I use them all the time on my WordPress sites because I can copy and paste the embed code right onto any page. But say I moved that site off of traditional WordPress and onto something more JAMstacky (maybe even a static site that hits the WordPress API, whatevs). I could still simply embed my Wufoo form. A Wufoo form can literally be put on any type of site, which is awesome since you lose no data and don’t change the experience at all when making a big move.

And, just in case you didn’t know, Wufoo has robust read and write APIs, so Wufoo really can come with you wherever you go.

Try it Now

The post Forms that Move With You with Wufoo appeared first on CSS-Tricks.

Multiple Background Clip

You know how you can have multiple backgrounds?

body { background-image: url(image-one.jpg), url(image-two.jpg);
}

That’s just background-image. You can set their position too, as you might expect. We’ll shorthand it:

body { background: url(image-one.jpg) no-repeat top right, url(image-two.jpg) no-repeat bottom left;
}

I snuck background-repeat in there just for fun. Another one you might not think of setting for multiple different backgrounds, though, is background-clip. In this linked article, Stefan Judis notes that this unlocks some pretty legit CSS-Trickery!

Direct Link to ArticlePermalink

The post Multiple Background Clip appeared first on CSS-Tricks.

The Importance of One-on-Ones

What do we mean by 1:1 (pronounced one-on-one)? This is typically a private conversation between an Engineering Manager/Lead and their Employee. I personally have been a Lead, a Manager, and also an Independent Contributor/Software Engineer, so I’ve sat at each side of the table. I’ve both had great experiences on each side and have made mistakes on each side. That said, I’m going to cover some meditations on the subject because 1:1s open opportunities for personal and professional growth when they’re effective.

What I’ve noticed about Software Engineering as a discipline, in particular, is that it has many people sharing posts about technical implementations and very few about engineering management. Management can influence and impact our ability to code efficiently and hone our craft, so it’s worth exploring publicly.

My thoughts on this change a lot and, like all humans, I’m always learning, so please don’t take any of these opinions as gospel. Think of them more like a dialogue where we can bounce ideas off one another.

Establishing baseline rules

I believe that 1:1s are crucial and should not be the kind of meeting anyone takes lightly, whether on the management or employee side. The meetings should have a regular cadence, scheduled either once a week or biweekly and only cancelled for pressing circumstances — and if they have to be cancelled, it’s a good practice to let the other person know why rather than simply removing it from the calendar.

It might be tempting to think remote working means fewer 1:1s, but it’s quite the opposite. Since each person is in a different space on a day-to-day basis, 1:1s help make up for sporadic contact by meeting regularly.

1:1s should be conducted in a space with the smallest amount of distractions possible. If you are in a room with one other person, shut off your computer and use a notepad so you won’t get notifications. If doing a 1:1 remotely, make sure you’re in a quiet place and that it has stable internet bandwidth. And, please, avoid taking 1:1s in a car or while running errands. It’s also worth trying to limit the time you spend in noisy environments, like cafes. Another tip: if you have to be outside, wear headphones. Again, this is all for the benefit of limiting distractions so that everyone’s focus is on the meeting itself.

Honestly, I would rather someone cancel on me or push the meeting off until they’re in a quiet place than take a call swarming with distractions. Nothing says, “I don’t value your time,” like multitasking during a 1:1 meeting. The whole purpose of the 1:1 should be to make the other person feel valuable and connected.

meeting between two people
📷 Credit: @rawpixel on Unsplash

So, why should we devote time to 1:1s anyway?

1:1s are crucial. If we constantly work on tasks without taking the time to step back and check in with our work, we risk being tactical rather than strategic. We risk working in a silo, which can lead to burnout and anxiety. We risk opportunities to spot errors early and reduce technical debt. At their root, 1:1s should reduce uncertainty by making us feel more connected to the rest of the team while clarifying intent.

For example, on the employee side, you might not be sure whether to invest your time in Task A or Task B and the progress of your commits slows down as a result. Which one is higher priority? On the manager side, you might not be sure what’s happening — the employee could be stuck on a problem. They could be burnt out, but it’s tough to be sure. It’s totally normal for someone to get stuck once in a while, but it’s common to not want to announce it in front of others, perhaps out of fear of embarrassment, among other things. A 1:1 is a good, safe, private place to explore concerns before they become tangible problems because they offer privacy that some open floor plans simply do not.

This privacy part is important. Candid exploration of high level topics, like career goals, or even low level topics, like code reviews, are best done and that is easier to do with one person in a private space rather than a full audience out in the open. At their best, 1:1s should create a good environment to resolve some of these issues.

Employees and managers alike should be fully invested in the meeting. This means using active body language that shows attention. This means emphasizing listening and speaking in turn without interrupting the other person.

Connection

Belonging is a core tenant of Maslow’s hierarchy of needs because, as humans, we’re designed for connectedness and kinship. I know this article is about engineering management, but engineers are no less in need of empathy and human connection than any other person in any other profession.

The reason I include this at all is because connecting with others on a personal level is something I really need to work on myself. I’m awkward. I’m an introvert. I don’t always know how to talk to people. But I do know that there have been plenty of 1:1s where I either felt heard or that I was hearing someone else. In other words, I felt in connected to the other person, be it through shared goals, personal similarities, or even common gripes about something.

A friend of mine mentioned that “people leave managers, not jobs.” This is, for the most part, so true! Simply taking the time to develop a connection where a manager and employee both know each other better creates a higher level of comfort that can go a long way towards many benefits, including employee retention.

It might be worth asking the other person what modality works best if you’re remote. Some people prefer video chats; some people prefer phone calls. That’s all part of fostering a better connection.

1:1s are more for employees than managers

Don’t let that headline give you pause. Yes, these meetings are for both parties. They really are. But here’s the thing: in the balance of power, the manager can always speak directly to the employee. The inverse isn’t always true. There are also dynamics between teammates. That means the manager’s job in a 1:1 is to provide a space for the employee to speak clearly and freely about concerns, particularly ones that might impact their performance.

Ideally, a manager will listen more than an employee, but a back and forth dialogue can be healthy, too. A 1:1 where a manager is speaking the most is probably the least productive. This isn’t team time; it’s time to give an employee the floor because it otherwise might not happen in other venues.

In my experience, it’s best if a manager first learns the an employee’s Ultimate Goals™. Where do they see themselves in five years? What kind of work they like to do most? What environments do they work in best and which ones are the most difficult? A manager can’t always facilitate the ideal situation, but having this information is still extremely valuable for cultivating a person’s career trajectory, for the work that needs to be done, and for a general understanding of what will keep people working well together.

Let’s say you have two employees: one wants to be a Principal Architect someday and another who tells you that they love refactoring. That actually gives you pretty good insight for a project that requires one person to drive direction and another to clean up the legacy code in preparation for the refactor!

Or, say you have an employee that wants to be Director someday but rarely helps others. You also concurrently get an intern. This is your chance to develop one’s mentoring skills and scale the other’s engineering skills.

When these meetings are focused on the employee instead of the manager, they help the employee feel heard and motivated, which can bolster their career and also give the manager the ability to make bigger decisions about how everyone works together to accomplish their individual and collective goals.

meeting between two people
📷 Credit: @rawpixel on Unsplash

Yes, agendas are required

Yes, even though 1:1s have a tendency to be informal because everyone already knows each other well, they’re way more successful when there’s an agenda, at least in my opinion. And no, it’s not important for the agendas to be super formal either. They could be a couple bullet points on a sheet of paper. Or even items added to a private Slack channel. What’s most important is that both parties come prepared to talk.

If both the manager and the employee have agendas, my preference is to either defer priority to the employee, or compare lists up front to prioritize items. It might be that the manager has to discuss something pressing and sensitive, like a team reorg that affects the employee’s agenda. Regardless, communication is key. In a best-case scenario, you’re both in lock step and that all agenda items actually overlap.

Employees: Sometimes weeks are tough and it’s easy to get frustrated. Taking time to write an agenda keeps the meeting from being all, “I hate everything and how could you have done me so wrong,” and more focused on actionable items. Why not just vent? Sure, there’s a time and place for venting, but the problem with it is that your manager is a person, and might not know exactly how to help you on an emotional level. Having specific topics and items make it facilitate more actionable feedback for your manager, and therefore, make them better able to support you.

Managers: Let’s face it, you’re probably juggling a million plates. (That metaphor might be wrong, but you catch my drift.) There’s a lot on your mind and most of it is confidential. Agenda give you the context you need to prevent wandering into topics you might not be at liberty to discuss. It also keeps things on track. Are there four more things you need to cover and you’re already 15 minutes into a 30-minute meeting? You’re less likely to pontificate about your early career or foray into irrelevant paths and stay focused on the task and human right in front of you.

Direction and Guidance

One thing that a 1:1 can be useful for is guidance. On a few occasions, I’ve checked in with an employee who’s communicated feeling like they’re in over their heads — whether they’ve overcommitted or have such a tall task in front of them, they’re not sure how to proceed and feel anxious to the point of paralysis.

As mentioned before, this is a great opportunity for a manager to reduce uncertainty. Some ways to do that:

  • Prioritize. If there’s too much work, spend time talking through the most important pieces, and even perhaps offer yourself as a shield from some of the work.
  • Make action items. Sometimes a task is too large and the employee needs help breaking it down into organized pieces making it easier to know where to start and how to move forward.
  • Clarify vision. People might feel overwhelmed because they don’t know why they’re doing something. If you can communicate the necessity of the work at hand, then it can align them with the goal of the project and make the work more rewarding and valuable.

One risk here is passive listening. For example, there’s a fine line between knowing when to let an employee vent and when that venting needs actionable solutions. Or both! I have no hard rules about when one is needed over the other, and I sometimes get this wrong myself. This is why eye contact and active listening is important. You’ll receive subtle cues from the person that help reveal what is needed in the situation.

If you’re an employee and your manager isn’t providing the listening mode you need from them, I think it’s OK to gently mention that. Your manager isn’t a mind reader, and in many cases, they haven’t even received management training to develop proper listening skills. It’s perfectly fine to say something along the lines of, “It would be really great if you could sit with me and help me prioritize all these tasks on my to do list,” or “I really need to vent right now, but some of the venting is stuff I think is valuable for you to know about.” Personally, I love it when someone tells me what they need. I’m usually trying to figure that out, so it takes out the guesswork.

Meeting adjourned…

You spend many waking hours at work. It’s important that your working relationships — particularly between manager and employee — are healthy and that you’re intentionally checking in with purpose, both in the short-term and the long-term.

1:1s may appear to be time hogs on the calendar, but over the long haul, you’ll find they save valuable time. As a manager, having a team of employees who feel valued, aligned and connected is about the best thing you can ask for. So, value them because you’ll get solid value in return.

More Resources