Here’s a great talk by Das Surma where he looks into what Houdini is and how much of it is implemented in browsers. If you’re unfamiliar with that, Houdini is a series of technologies and APIs that gives developers low level access to how CSS properties work in a fundamental way. Check out Ana Tudor’s deep dive into its impact on animations for some incredible examples of it in practice.
What I particularly like about this video is the way Das mentions the CSS Paint API which lets you do a bunch of bizarre things with CSS, such as creating „squircle” shapes and changing how borders work. It looks wonderfully robust and it should give us super powers in the near future. Ruth John wrote up this extensive overview on the topic earlier this year and it’s worth a read as well.
When you need to add icons to your interface, the whole process can really suck. “Should I use all these default bootstrap icons? Maybe I’ll just use the same Google Material icons for the hundredth time?”
Some important yet often overlooked things to consider when choosing an icon set includes, the size of the icons, style, consistency, and quantity. It’s frustrating to find icons that only cover half of the use cases you need.
We constantly felt this frustration too and decided to do something about it. This ultimately led to creating Streamline icon set.
Now in version 3.0, Streamline contains a whopping 30,000 icons in three distinct weights, similar to a font family. There are tons of options to pick the perfect icon for any interface you’re working with, whether it’s a big web application, documentation, or a marketing site.
„I own several icon sets but the one that I return to over and over is the copious Streamline pack, which almost always seems to have just the pictogram I need when I dig into its catalog.”
If you’re an IconJar user, you can also search for icons by name and drag and drop them into your project folder. We’re currently under development on this functionality for our web viewer too.
Every Streamline Icon pack comes with the following file types: .svg, .iconjar, .sketch, .fig, .ai, .pdf, .png, .xd.
So now matter how you like to work with icons, you have the file types you need.
„Streamline 3.0 is one of the most versatile and detailed icon packs I’ve ever used. The structure and hierarchy make it super easy to work with. This is an amazing product. Bravo, Vincent.”
—Stephanie Walter, UX & UI Designer
Optimized SVG
The SVG versions of Streamline is already dev-ready with proper viewbox tags in place and currentColor set as the color properties for all strokes and fills. You can pop in Streamline using your favorite SVG technique and start changing the color of the icons with CSS right out of the gate.
Every weight—light, regular, and bold—was designed with a very consistent style to give you tons of consistency within your interface.
Light
The classic Streamline style with bits of detail here and there. Designed with 1px stroke on a 24px grid. The Light icons are great for interfaces that need lots of fun personality. They also work well scaled up to 48px as small illustrations.
Regular
A new minimal and geometric style. Designed with a 1.5px stroke on a 24px grid. These are perfect to use on clean and modern web interfaces.
Bold
A new solid style akin to the latest iOS guidelines. Designed with fills and a 2px stroke on a 24px grid. The bold style gives a little more punch for an iOS style interface.
Put Streamline to work for you
There are two different package types available—Essential and Ultimate.
Essential contains 14 categories all related to interfaces and web design, whereas the Ultimate pack contains all 53 categories, including things like Pets, Weather, Finance, Outdoors, Transportation, and so much more.
I recently had an opportunity to work on a fantastic research and development project at Netguru. The goal of project (codename: „Wordguru”) was to create a card game that anyone can play with their friends. You can see the outcome here.
One element of the development process was to create an interactive card stack. The card stack had a set of requirements, including:
It should contain a few cards from the collection.
The first card should be interactive.
The user should be able to swipe the card in different directions that indicate an intent to accept, reject or skip the card.
This article will explain how to create that and make it interactive using Vue.js and interact.js. I created an example for you to refer to as we go through the process of creating a component that is in charge of displaying that card stack and a second component that is responsible for rendering a single card and managing user interactions in it.
Let’s start by creating a component that will show a card, but without any interactions just yet. We’ll call this file GameCard.vue and, in the component template, we’ll render a card wrapper and the keyword for a specific card. This is the file we’ll be working in throughout this post.
In the script section of the component, we receive the prop card that contains our card content as well as an isCurrent prop that gives the card a distinct look when needed.
Now that we have a single card, let’s create our card stack.
This component will receive an array of cards and render the GameCard for each card. It’s also going to mark the first card as the current card in the stack so a special styling is applied to it.
Here’s what we’re looking at so far, using the styles pulled from the demo:
At this point, our card looks complete, but isn’t very interactive. Let’s fix that in the next step!
Step 3: Add interactivity to GameCard component
All our interactivity logic will live in the GameCard component. Let’s start by allowing the user to drag the card. We will use interact.js to deal with dragging.
We’ll set the interactPosition initial values to 0 in the script section. These are the values that indicate a card’s order in the stack when it’s moved from its original position.
In the mounted lifecycle hook, we make use of the interact.js and its draggable method. That method allows us to fire a custom function each time the element is dragged (onmove). It also exposes an event object that carries information about how far the element is dragged from its original position. Each time user drags the card, we calculate a new position of the card and set it on the interactPosition property. That triggers our transformString computed property and sets new value of transform on our card.
We use the interact onend hook that allows us to listen when the user releases the mouse and finishes the drag. At this point, we will reset the position of our card and bring it back to its original position: { x: 0, y: 0 }.
We also need to make sure to remove the card element from the Interactable object before it gets destroyed. We do that in the beforeDestroy lifecycle hook by using interact(target).unset(). That removes all event listeners and makes interact.js completely forget about the target.
We need to add one thing in our template to make this work. As our transformString computed property returns a string, we need to apply it to the card component. We do that by binding to the :style attribute and then passing the string to the transform property.
With that done, we have created interaction with our card — we can drag it around!
You may have noticed that the behavior isn’t very natural, specifically when we drag the card and release it. The card immediately returns to its original position, but it would be more natural if the card would go back to initial position with animation to smooth the transition.
That’s where transition comes into play! But adding it to our card introduces another issue: there’s a lag in the card following as it follows the cursor because transition is applied to the element at all times. We only want it applied when the drag ends. We can do that by binding one more class (isAnimating) to the component.
We can add and remove the animation class by changing the isInteractAnimating property.
The animation effect should be applied initially and we do that by setting our property in data.
In the mounted hook where we initialize interact.js, we use one more interact hook (onstart) and change the value of isInteractAnimating to false so that the animation is disabled when the during the drag.
We’ll enable the animation again in the onend hook, and that will make our card animate smoothly to its original position when we release it from the drag.
We also need to update transformString computed property and add a guard to recalculate and return a string only when we are dragging the card.
Our card stack is ready for second set of interactions. We can drag the card around, but nothing is actually happening — the card is always coming back to its original place, but there is no way to get to the second card.
This will change when we add logic that allows the user to accept and rejecting cards.
Step 4: Detect when the card is accepted, rejected, or skipped
The card has three types of interactions:
Accept card (on swipe right)
Reject card (on swipe left)
Skip card (on swipe down)
We need to find a place where we can detect if the card was dragged from its initial position. We also want to be sure that this check will happen only when we finish dragging the card so the interactions do not conflict with the animation we just finished.
We used that place earlier smooth the transition during animation — it’s the onend hook provided by the interact.draggable method.
Let’s jump into the code.
First, we need to store our threshold values. Those values are the distances as the card is dragged from its original position and allows us to determine if the card should be accepted, rejected, or skipped. We use X axis for right (accept) and left (reject), then use the Y axis for downward movement (skip).
We also set coordinates where we want to place a card after it gets accepted, rejected or skipped (coordinates out of user’s sight).
Since those values will not change, we will keep them in the static property of our component, which can be accessed with this.$options.static.interactYThreshold.
We need to check if any of our thresholds were met in our onend hook and then fire the appropriate method that happened. If no threshold is met, then we reset the card to its initial position.
OK, now we need to create a playCard method that’s responsible for handling those interactive actions.
Step 5: Establish the logic to accept, reject, and skip cards
We will create a method that accepts a parameter telling us the user’s intended action. Depending on that parameter, we will set the final position of the current card and emit the accept, reject, or skip event. Let’s go step by step.
First, our playCard method will remove the card element from the Interactable object so that it stops tracking drag events. We do that by using interact(target).unset().
Secondly, we set the final position of the active card depending on the user’s intention. That new position allows us to animate the card and remove it from the user’s view.
Next, we emit an event up to the parent component so we can deal with our cards (e.g. change the current card, load more cards, shuffle the cards, etc.). We want to follow the DDAU principle that states a component should refrain from mutating data it doesn’t own. Since our cards are passed down to our component, it should emit an event up to the place from where those cards come.
Lastly, we hide the card that was just played and add a timeout that allow the card to animate out of view.
Next we created another component that renders the cards in a stack.
Thirdly, we implemented interact.js to allow interactive dragging.
Then we detected when the user wants takes an action with the current card.
Finally, we established the to handle those actions.
Phew, we covered a lot! Hopefully this gives you both a new trick in your toolbox as well as a hands-on use case for Vue. And, if you’ve ever had to build something similar, please share in the comments because it would be neat to compare notes.
There is good news on this front! The standards bodies that be have moved toward a standardizing methods to style scrollbars, starting with the gutter (or width) of them. The main property will be scrollbar-gutter and Geoff has written it up here. Hopefully Autoprefixer will help us as the spec is finalized and browsers start to implement it so we can start writing the standardized version and get any prefixed versions from that.
The subject of scaling CSS came up a lot in a recent ShopTalk Show with Ben Frain. Ben has put a lot of thought into the subject, even writing a complete book on it, Enduring CSS, which is centered around a whole ECSS methodology.
He talked about how there are essentially two solutions for styling at scale:
Total isolation
Total abstraction
Total isolation is some version of writing styles scoped to some boundary that you’ve set up (like a component) in which those styles don’t leak in or out.
Total abstraction is some version of writing styles that are global, yet so generic and re-usable, that they have no unintended side effects.
Total isolation might come from <style scoped> in a .vue file, CSS modules in which CSS class selectors and HTML class attributes are dynamically generated gibberish, or a CSS-in-JS project, like glamerous. Even strictly-followed naming conventions like BEM can be a form of total isolation.
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.
It’s the middle ground that has problems. It’s using a naming methodology, but not holding strictly to it. It’s using some styles in components, but also having a global stylesheet that does random other things. Or, it’s having lots of developers contributing to a styling system that has no strict rules and mixes global and scoped styles. Any stylesheet that grows and grows and grows. Fighting it by removing some unused styles isn’t a real solution (and here’s why).
Note that the web is a big place and not all projects need a scaling solution. A huge codebase with hundreds of developers that needs to be maintained for decades absolutely does. My personal site does not. I’ve had my fair share of styling problems, but I’ve never been so crippled by them that I’ve needed to implement something as strict as Atomic CSS (et al.) to get work done. Nor at at any job I’ve had so far. I see the benefits though.
Imagine the scale of Twitter.com over a decade! Nicolas has a great thread where he compares Twitter’s PWA against Twitter’s legacy desktop website.
The legacy site’s CSS is what happens when hundreds of people directly write CSS over many years. Specificity wars, redundancy, a house of cards that can’t be fixed. The result is extremely inefficient and error-prone styling that punishes users and developers alike.
I find GraphQL extremely fun and empowering tech to work with, even as a novice just getting started. You’ve probably heard the elevator pitch before: it allows you to ask for exactly the data you need whenever you need it (probably at the component level), and it arrives as lovely JSON data for your usage.
I see it used as part of modern website builds all the dang time. The overall vibe is, „I want to do whatever I want on the front end, and that actually allows for more back-end choices as well.” And by „whatever” on the front end, that generally means a fancy SPA-ish JavaScript-powered thing or a static-site generator-ish thing.
Here’s a quick smattering of articles that are everywhere these days. Instead of the actual article titles, I’ll rename with the stack parts.
I find GraphQL extremely fun and empowering tech to work with, even as a novice just getting started. You’ve probably heard the elevator pitch before: it allows you to ask for exactly the data you need whenever you need it (probably at the component level), and it arrives as lovely JSON data for your usage.
I see it used as part of modern website builds all the dang time. The overall vibe is, „I want to do whatever I want on the front end, and that actually allows for more back-end choices as well.” And by „whatever” on the front end, that generally means a fancy SPA-ish JavaScript-powered thing or a static-site generator-ish thing.
Here’s a quick smattering of articles that are everywhere these days. Instead of the actual article titles, I’ll rename with the stack parts.
Using render props in React is a technique for efficiently re-using code. According to the React documentation, „a component with a render prop takes a function that returns a React element and calls it instead of implementing its own render logic.” To understand what that means, let’s take a look at the render props pattern and then apply it to a couple of light examples.
The render props pattern
In working with render props, you pass a render function to a component that, in turn, returns a React element. This render function is defined by another component, and the receiving component shares what is passed through the render function.
Imagine, if you will, that our App is a gift box where App itself is the bow on top. If the box is the component we are creating and we open it, we’ll expose the props, states, functions and methods needed to make the component work once it’s called by render().
The render function of a component normally has all the JSX and such that form the DOM for that component. Instead, this component has a render function, this.props.render(), that will display a component that gets passed in via props.
In the Wrapper component, we specify the methods and state what gets exposed to the wrapped component. For this example, we need the increment and decrement methods. We have our default count set as 0. The logic is to either increment or decrement count depending on the method that is triggered, starting with a zero value.
If you take a look at the return() method, you’ll see that we are making use of this.props.render(). It is through this function that we pass methods and state from the Wrapper component so that the component that is being wrapped by it will make use of it.
To use it for our App component, the component will look like this:
The gain lies in the reusable power of render props, let’s create a component that can be used to handle a list of data which is obtainable from an API.
What do we want from the wrapper component this time? We want to pass the source link for the data we want to render to it, then make a GET request to obtain the data. When the data is obtained we then set it as the new state of the component and render it for display.
The data link will be passed as props to the Wrapper component. When we get the response from the server, we update list using what is returned from the server. The request is made to the server after the component mounts.
You can see that we pass the link as a prop, then we use ES6 de-structuring to get the state of the Wrapper component which is then rendered. The first time the component loads, we display loading text, which is replaced by the list of items once we get a response and data from the server.
The App component here is a class component since it does not manage state. We can transform it into a functional stateless component.
We don’t generally think of CSS animations or transitions inside of email, or really any movement at all outside of an awkward occasional GIF. But there is really no reason you can’t use them inside HTML emails, particularly if you do it in a progressive enhancement-friendly way. Like, you could style a link with a hover state and a shaking animation, but if the animation (or even the hover) doesn’t work, it’s still a functional link. Heck, you can use CSS grid in email, believe it or not.
Jason Rodriguez just wrote Understanding CSS Animations in Email: Transitions and Keyframe Animations that covers some of the possibilities. On the supported list of email clients that support CSS transitions and keyframe animations is Apple Mail, Outlook, and AOL mail, among others.
I had to build a UI recently and (for the first time in a long while) I didn’t have the option of using React.js, which is my preferred solution for UI these days. So, I looked at what the built-in browser APIs had to offer and saw that using custom elements (aka Web Components) may just be the remedy that this React developer needed.
Custom elements can offer the same general benefits of React components without being tied to a specific framework implementation. A custom element gives us a new HTML tag that we can programmatically control through a native browser API.
Let’s talk about the benefits of component-based UI:
Encapsulation – concerns scoped to that component remain in that component’s implementation
Reusability – when the UI is separated into more generic pieces, they’re easier to break into patterns that you’re more likely to repeat
Isolation – because components are designed to be encapsulated and with that, you get the added benefit of isolation, which allows you scope bugs and changes to a particular part of your application easier
Use cases
You might be wondering who is using custom elements in production. Notably:
GitHub is using custom elements for their modal dialogs, autocomplete and display time.
To break this down further, we have a component that has its own state, which is the repo details. Initially, we set it to be null because we don’t have any of that data yet, so we’ll have a loading indicator while the data is fetched.
During the React lifecycle, we’ll use fetch to go get the data from GitHub, set up the card, and trigger a re-render with setState() after we get the data back. All of these different states the UI takes are represented in the render() method.
Defining / Using a Custom Element
Doing this with custom elements is a little different. Like the React component, our custom element will take a single attribute — again, the name of the repository — and manage its own state.
To start, all we need to do to define and register a custom element is create a class that extends the HTMLElement class and then register the name of the element with customElements.define().
class OurCustomElement extends HTMLElement {}
window.customElements.define('our-element', OurCustomElement);
And we can call it:
<our-element></our-element>
This new element isn’t very useful, but with custom elements, we get three methods to expand the functionality of this element. These are almost analogous to React’s lifecycle methods for their Component API. The two lifecycle-like methods most relevant to us are the disconnectedCallBack and the connectedCallback and since this is a class, it comes with a constructor.
Name
Called when
constructor
An instance of the element is created or upgraded. Useful for initializing state, settings up event listeners, or creating Shadow DOM. See the spec for restrictions on what you can do in the constructor.
connectedCallback
The element is inserted into the DOM. Useful for running setup code, such as fetching resources or rendering UI. Generally, you should try to delay work until this time
disconnectedCallback
When the element is removed from the DOM. Useful for running clean-up code.
To implement our custom element, we’ll create the class and set up some attributes related to that UI:
By calling super() in our constructor, the context of this is the element itself and all the DOM manipulation APIs can be used. So far, we’ve set the default repository details to null, gotten the repo name from element’s attribute, created an endpoint to call so we don’t have to define it later and, most importantly, set the initial HTML to be a loading indicator.
In order to get the details about that element’s repository, we’re going to need to make a request to GitHub’s API. We’ll use fetch and, since that’s Promise-based, we’ll use async and await to make our code more readable. You can learn more about the async/await keywords here and more about the browser’s fetch API here. You can also tweet at me to find out whether I prefer it to the Axios library. (Hint, it depends if I had tea or coffee with my breakfast.)
Now, let’s add a method to this class to ask GitHub for details about the repository.
Next, let’s use the connectedCallback method and the Shadow DOM to use the return value from this method. Using this method will do something similar as when we called Repository.componentDidMount() in the React example. Instead, we’ll override the null value we initially gave this.repoDetails — we’ll use this later when we start to call the template to create the HTML.
You’ll notice that we’re calling methods related to the Shadow DOM. Besides being a rejected title for a Marvel movie, the Shadow DOM has its own rich API worth looking into. For our purposes, though, it’s going to abstract the implementation of adding innerHTML to the element.
Now we’re assigning the innerHTML to be equal to the value of this.template. Let’s define that now:
class Repository extends HTMLElement {
get template() {
const repo = this.repoDetails;
// if we get an error message let's show that back to the user
if (repo.message) {
return `<div class="Card Card--error">Error: ${repo.message}</div>`
} else {
return `
<div class="Card">
<aside>
<img width="48" height="48" class="Avatar" src="${repo.owner.avatar_url}" alt="Profile picture for ${repo.owner.login}" />
</aside>
<header>
<h2 class="Card__title">${repo.full_name}</h2>
<span class="Card__meta">${repo.description}</span>
</header>
</div>
`
}
}
}
That’s pretty much it. We’ve defined a custom element that manages its own state, fetches its own data, and reflects that state back to the user while giving us an HTML element to use in our application.
After going through this exercise, I found that the only required dependency for custom elements is the browser’s native APIs rather than a framework to additionally parse and execute. This makes for a more portable and reusable solution with similar APIs to the frameworks you already love and use to make your living.
There are drawbacks of using this approach, of course. We’re talking about various browser support issues and some lack of consistency. Plus, working with DOM manipulation APIs can be very confusing. Sometimes they are assignments. Sometimes they are functions. Sometimes those functions take a callback and sometimes they don’t. If you don’t believe me, take a look at adding a class to an HTML element created via document.createElement(), which is one of the top five reasons to use React. The basic implementation isn’t that complicated but it is inconsistent with other similar document methods.
The real question is: does it even out in the wash? Maybe. React is still pretty good at the things it’s designed to be very very good at: the virtual DOM, managing application state, encapsulation, and passing data down the tree. There’s next to no incentive to use custom elements inside that framework. Custom elements, on the other hand, are simply available by virtue of building an application for the browser.