Front End Web Development

Dealing with overflow and position: sticky;

Css Tricks - Mon, 02/25/2019 - 10:44am

Any overflow value other than visible and no height is the enemy of child elements with position: sticky;. It's like that element is ready to stick when the parent scrolls, but it never does because the height is unconstrained. Adding a fixed height can solve the issue, but that's not always desirable.

Dannie Vinther digs into a way of dealing with that. The end result is avoiding that situation all together by removing the element that wants to be sticky from the element that needs an overflow. But as soon as you do that, the elements no longer scroll together since they aren't siblings. The use case here is a table with sticky headers on vertical scrolling and allowing for horizontal scrolling as well. Dannie uses a script to sync the scroll positions.

Direct Link to ArticlePermalink

The post Dealing with overflow and position: sticky; appeared first on CSS-Tricks.

Responsive Designs and CSS Custom Properties: Defining Variables and Breakpoints

Css Tricks - Mon, 02/25/2019 - 5:22am

CSS custom properties (a.k.a. CSS variables) are becoming more and more popular. They finally reached decent browser support and are slowly making their way into various production environments. The popularity of custom properties shouldn’t come as a surprise, because they can be really helpful in numerous use cases, including managing color palettes, customizing components, and theming. But CSS variables can also be really helpful when it comes to responsive design.

Article Series:
  1. Defining Variables and Breakpoints (This Post)
  2. Building a Flexible Grid System

Let’s consider an <article> element with a heading and a paragraph inside:

<article class="post"> <h2 class="heading">Post's heading</h2> <p class="paragraph"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laudantium numquam adipisci recusandae officiis dolore tenetur, nisi, beatae praesentium, soluta ullam suscipit quas? </p> </article>

It’s a common scenario in such a case to change some sizes and dimensions depending on the viewport’s width. One way to accomplish this is by using media queries:

.post { padding: 0.5rem 1rem; margin: 0.5rem auto 1rem; } .heading { font-size: 2rem; } @media (min-width: 576px) { .post { padding: 1rem 2rem; margin: 1rem auto 2rem; } .heading { font-size: 3rem; } }

See the Pen
#1 Building responsive features with CSS custom properties
by Miko?aj (@mikolajdobrucki)
on CodePen.

Such an approach gives us an easy way to control CSS properties on different screen sizes. However, it may be hard to maintain as the complexity of a project grows. When using media queries, keeping code readable and DRY at the same time quite often turns out to be challenging.

The most common challenges when scaling this pattern include:

  • Repeated selectors: Apart from bloating code with multiple declarations, it also makes future refactoring more difficult, e.g. every time a class name changes it requires remembering to update it in multiple places.
  • Repeated properties: Notice that when overwriting CSS rules within media queries, it requires repeating the entire declaration (e.g. font-size: 3rem;) even though it’s just the value (3rem) that actually changes.
  • Repeated media queries: To keep responsive styles contextual, it’s a common practice to include the same media queries in multiple places, close to the styles they override. Unfortunately, it not only makes code heavier, but also might make breakpoints much harder to maintain. On the other hand, keeping all responsive styles in one place, away from their original declarations, may be very confusing: we end up with multiple references to the same elements sitting in completely different places.

We can argue that repeated declarations and queries shouldn’t be such a big deal with proper file compression enabled, at least as long as we’re referring to performance. We can also merge multiple queries and optimize your code with post-processing tools. But wouldn’t it be easier to avoid these issues altogether?

There’s a lot of ways to avoid the issues listed above. One of them, that we will explore in this article, is to use CSS custom properties.

Using CSS variables for property values

There are plenty of amazing articles on the web explaining the concept of CSS custom properties. If you haven’t got chance to get familiar with them yet, I would recommend starting with one of the beginner articles on this topic such as this awesome piece by Serg Hospodarets as we are not going to get into details of the basic usage in this article.

The most common way of utilizing CSS custom properties in responsive design is to use variables to store values that change inside of media queries. To accomplish this, declare a variable that holds a value that is supposed to change, and then reassign it inside of a media query:

:root { --responsive-padding: 1rem; } @media (min-width: 576px) { :root { --responsive-padding: 2rem; } } .foo { padding: var(--responsive-padding); }

Assigning variables to the :root selector is not always a good idea. Same as in JavaScript, having many global variables is considered a bad practice. In real life, try to declare the custom properties in the scope they will actually be used.

This way, we are avoiding multiple rules of the .foo class. We are also separating the logic (changing values) from the actual designs (CSS declarations). Adapting this approach in our example from above gives us the following CSS:

.post { --post-vertical-padding: 0.5rem; --post-horizontal-padding: 1rem; --post-top-margin: 0.5rem; --post-bottom-margin: 1rem; --heading-font-size: 2rem; } @media (min-width: 576px) { .post { --post-vertical-padding: 1rem; --post-horizontal-padding: 2rem; --post-top-margin: 1rem; --post-bottom-margin: 2rem; --heading-font-size: 3rem; } } .post { padding: var(--post-vertical-padding) var(--post-horizontal-padding); margin: var(--post-top-margin) auto var(--post-bottom-margin); } .heading { font-size: var(--heading-font-size); }

See the Pen
#2 Building responsive features with CSS custom properties
by Miko?aj (@mikolajdobrucki)
on CodePen.

Notice that the use of variables in shorthand properties (e.g. padding, margin or font) allow some very interesting repercussions. As custom properties may hold almost any value (more on this later), even an empty string, it’s unclear how the value of a shorthand property will be separated out into longhand properties that are used in the cascade later. For example, the auto used in the margin property above may turn out to be a top-and-bottom margin, a left-and-right margin, a top margin, a right margin, a bottom margin or a left margin — it all depends on the values of the custom properties around.

It’s questionable whether the code looks cleaner than the one from the previous example, but on a larger scale, it’s definitely more maintainable. Let’s try to simplify this code a bit now.

Notice that some values are repeated here. What if we try to merge duplicate variables together? Let’s consider the following alteration:

:root { --small-spacing: 0.5rem; --large-spacing: 1rem; --large-font-size: 2rem; } @media (min-width: 576px) { :root { --small-spacing: 1rem; --large-spacing: 2rem; --large-font-size: 3rem; } } .post { padding: var(--small-spacing) var(--large-spacing); margin: var(--small-spacing) auto var(--large-spacing); } .heading { font-size: var(--large-font-size); }

See the Pen
#3 Building responsive features with CSS custom properties
by Miko?aj (@mikolajdobrucki)
on CodePen.

It looks cleaner but is it actually better? Not necessarily. For the sake of flexibility and readability, this may not be the right solution in every case. We definitely shouldn’t merge some variables just because they accidentally turned out to hold the same values. Sometimes, as long as we’re doing this as a part of a well thought out system, it may help us simplify things and preserve consistency across the project. However, in other cases, such a manner may quickly prove to be confusing and problematic. Now, let’s take a look at yet another way we can approach this code.

Using CSS variables as multipliers

CSS custom properties are a fairly new feature to the modern web. One of the other awesome features that rolled out in the last years is the calc() function. It lets us perform real math operations in live CSS. In terms of the browser support, it’s supported in all browsers that support CSS custom properties.

calc() tends to play very nicely with CSS variables, making them even more powerful. This means we can both use calc() inside custom properties and custom properties inside calc()!

For example, the following CSS is perfectly valid:

:root { --size: 2; } .foo { --padding: calc(var(--size) * 1rem); /* 2 × 1rem = 2rem */ padding: calc(var(--padding) * 2); /* 2rem × 2 = 4rem */ }

Why does this matter to us and our responsive designs? It means that we can use a calc() function to alter CSS custom properties inside media queries. Let’s say we have a padding that should have a value of 5px on mobile and 10px on desktop. Instead of declaring this property two times, we can assign a variable to it and multiply it by two on larger screens:

:root { --padding: 1rem; --foo-padding: var(--padding); } @media (min-width: 576px) { :root { --foo-padding: calc(var(--padding) * 2); } } .foo { padding: var(--foo-padding); }

Looks fine, however all the values (--padding, calc(--padding * 2)) are away from their declaration (padding). The syntax may also be pretty confusing with two different padding variables (--padding and --foo-padding) and an unclear relationship between them.

To make things a bit clearer, let’s try to code it the other way around:

:root { --multiplier: 1; } @media (min-width: 576px) { :root { --multiplier: 2; } } .foo { padding: calc(1rem * var(--multiplier)); }

This way, we accomplished the same computed output with much cleaner code! So, instead of using a variable for an initial value of the property (1rem), a variable was used to store a multiplier (1 on small screens and 2 on larger screens). It also allows us to use the --multiplier variable in other declarations. Let’s apply this technique to paddings and margins in our previous snippet:

:root { --multiplier: 1; } @media (min-width: 576px) { :root { --multiplier: 2; } } .post { padding: calc(.5rem * var(--multiplier)) calc(1rem * var(--multiplier)); margin: calc(.5rem * var(--multiplier)) auto calc(1rem * var(--multiplier)); }

Now, let’s try to implement the same approach with typography. First, we’ll add another heading to our designs:

<h1 class="heading-large">My Blog</h1> <article class="post"> <h2 class="heading-medium">Post's heading</h2> <p class="paragraph"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laudantium numquam adipisci recusandae officiis dolore tenetur, nisi, beatae praesentium, soluta ullam suscipit quas? </p> </article>

With multiple text styles in place, we can use a variable to control their sizes too:

:root { --headings-multiplier: 1; } @media (min-width: 576px) { :root { --headings-multiplier: 3 / 2; } } .heading-medium { font-size: calc(2rem * var(--headings-multiplier)) } .heading-large { font-size: calc(3rem * var(--headings-multiplier)) }

You may have noticed that 3 / 2 is not a valid CSS value at all. Why does it not cause an error then? The reason is that the syntax for CSS variables is extremely forgiving, which means almost anything can be assigned to a variable, even if it’s not a valid CSS value for any existing CSS property. Declared CSS custom properties are left almost entirely un-evaluated until they are computed by a user agent in certain declarations. So, once a variable is used in a value of some property, this value will turn valid or invalid at the computed-value time.

Oh, and another note about that last note: in case you’re wondering, I used a value of 3 / 2 simply to make a point. In real life, it would make more sense to write 1.5 instead to make the code more readable.

Now, let’s take a look at the finished live example combining everything that we discussed above:

See the Pen
#4 Building responsive features with CSS custom properties
by Miko?aj (@mikolajdobrucki)
on CodePen.

Again, I would never advocate for combining calc() with custom properties to make the code more concise as a general rule. But I can definitely imagine scenarios in which it helps to keep code more organized and maintainable. This approach also allows the weight of CSS to be significantly reduced, when it’s used wisely.

In terms of readability, we can consider it more readable once the underlying rule is understood. It helps to explain the logic and relations between values. On the other hand, some may see it as less readable, because it’s tough to instantly read what a property holds as a value without first doing the math. Also, using too many variables and calc() functions at once may unnecessarily obscure code and make it harder to understand, especially for juniors and front-end developers who are not focused on CSS.

Conclusion

Summing up, there’s a lot of ways to use CSS custom properties in responsive design, definitely not limited to the examples shown above. CSS variables can be used simply to separate the values from the designs. They can also be taken a step further and be combined with some math. None of the presented approaches is better nor worse than the others. The sensibility of using them depends on the case and context.

Now that you know how CSS custom properties can be used in responsive design, I hope you will find a way to introduce them in your own workflow. Next up, we’re going to look at approaches for using them in reusable components and modules, so let's check that out.

The post Responsive Designs and CSS Custom Properties: Defining Variables and Breakpoints appeared first on CSS-Tricks.

Using CSS Grid the right way

Css Tricks - Fri, 02/22/2019 - 12:59pm

Violet Peña has shared her recommendations for using CSS Grid. They basically boil down to these high-level points:

  1. Use names instead of numbers for setting up our grid columns.
  2. fr should be our flexible unit of choice.
  3. We don’t really need a grid system anymore.

Although this is all great advice and Violet provides a few examples to support her recommendations, I particularly like what she has to say about learning CSS Grid:

“Learning” CSS Grid requires developing working knowledge of many new properties that don’t just describe one aspect of appearance or behavior, but feed into a completely new layout system. This system includes around 18 properties which use paradigms and syntax rarely (or never) seen anywhere else in the CSS spec.

This means that CSS Grid has a pretty high skill floor — a developer needs to learn and internalize lots of new information in order to be effective with it. Once you’re above that skill floor, Grid is an amazing ally in layout creation. Below that skill floor, Grid is an encumbrance. You wonder why you’re bothering to use it at all, since it seems to require lots of additional work for little reward.

In this post, I want to help you overcome that skill floor by showing you the most effective ways to leverage the Grid spec.

Also this post reminded me that, although I’m not sure why, I tend to avoid naming my grid columns up. Like in this bit of code that Violet walks us through:

.container { display: grid; grid-template-columns: [sidebar] 3fr [content] 4fr; }

Now we can use the sidebar or content names when we define our grid-column like this:

.content { grid-column: content; }

I really like that! It seems super easy to read and if we wanted to change the size of our .content, class then it only requires going back to where the grid is defined in the first place. Anyway, I’ll be sure to name my grid columns from here on out.

Direct Link to ArticlePermalink

The post Using CSS Grid the right way appeared first on CSS-Tricks.

Writing Animations That Bring Your Site to Life

Css Tricks - Fri, 02/22/2019 - 7:36am

Web animation is one of the factors that can strongly enhance your website’s look and feel. Sadly, unlike mobile apps, there aren’t as many websites using animation to their benefit as you would think. We don’t want to count yours among those, so this article is for you and anyone else looking for ways to use animation for a better user experience! Specifically, we’re going to learn how to make web interactions delightful using CSS animations.

Here’s what we’re going to build together:

Live Demo GitHub Repo

Before we move ahead, it’s worth mentioning that I’m going to assume you have at least some familiarity with modern front-end frameworks and a basic understanding of CSS animations. If you don’t, then no fear! CSS-Tricks has a great guides on React and Vue, as well as a thorough almanac post on the CSS animation property.

Good? OK, let’s talk about why we’d want to use animation in the first place and cover some baseline information about CSS animations.

Why would we to animate anything?

We could probably do an entire post on this topic alone. Oh, wait! Sarah Drasner already did that and her points are both poignant and compelling.

But, to sum things up based on my own experiences:

  • Animations enhance the way users interact with an interface. For example, smart animations can reduce cognitive load by giving users better context between page transitions.
  • They can provide clear cues to users, like where we want them to focus attention.
  • Animations serve as another design pattern in and of themselves, helping users to get emotionally attached to and engage with the interface.
  • Another benefit of using animations is that they can create a perception that a site or app loads faster than it actually does.
A couple of house rules with animations

Have you ever bumped into a site that animates all the things? Wow, those can be jarring. So, here’s a couple of things to avoid when working with animations so our app doesn’t fall into the same boat:

  • Avoid animating CSS properties other than transform and opacity. If other properties have to be animated, like width or height, then make sure there aren’t a lot of layout changes happening at the same time. There’s actually a cost to animations and you can see exactly how much by referring to CSS Triggers.
  • Also, just because animations can create perceived performance gains, there’s actually a point of diminishing return when it comes to using them. Animating too many elements at the same time may result in decreased performance.

Now we can get our hands dirty with some code!

Let’s build a music app

We’re going to build the music app we looked at earlier, which is inspired by Aurélien Salomon’s Dribbble shot. I chose this example so that we can focus on animations, not only within a component, but also between different routes. We’ll build this app using Vue and create animations using vanilla (i.e. no framework) CSS.

Animations should go hand-in-hand with UI development. Creating UI before defining their movement is likely to cost much more time. In this case, the Dribbble shot provides that scope for us.

Let’s start with the development.

Step 1: Spin up the app locally

First things first. We need to set up a new Vue project. Again, we’re assuming some base-level understanding of Vue here, so please check out the Learning Vue guide for more info on setting up.

We need a couple of dependencies for our work, notably vue-router for transitioning between views and sass-loader so we can write in Sass and compile to CSS. Here’s a detailed tutorial on using routes and Sass can be installed by pointing the command line at the project directory and using npm install -D sass-loader node-sass.

We have what we need!

Step 2: Setting up routes

For creating routes, we’re first going to create two bare minimum components — Artists.vue and Tracks.vue. We’ll drop a new file in the src folder called router.js and add routes for these components as:

import Vue from 'vue' import Router from 'vue-router' import Artists from './components/Artists.vue' import Tracks from './components/Tracks.vue' Vue.use(Router) export default new Router({ mode: 'history', routes: [ { path: '/', name: 'artists', component: Artists }, { path: '/:id', name: 'tracks', component: Tracks } ] })

Import router.js into the main.js and inject it to the Vue instance. Lastly, replace the content of your App.vue by <router-view/>.

Step 3: Create the components and content for the music app

We need two components that we’ll transition between with animation. Those are going to be:

  1. Artists.vue: a grid of artists
  2. Tracks.vue: An artist image with a back button

If you wanna jump ahead a bit, here are some assets to work with:

  1. Images and sample data in JSON format.
  2. Content for the components

When all is said and done, the two views will come out to something like this:

Artists.vue (left) and Tracks.vue (right) Step 4: Animate!

Here we are, the part we’ve really wanted to get to all this time. The most important animation in the app is transitioning from Artists to Tracks when clicking on an artist. It should feel seamless where clicking on an artist image puts that image in focus while transitioning from one view into the next. This is exactly the type of animation that we rarely see in apps but can drastically reduce cognitive load for users.

To make sure we’re all on the same page, we’re going to refer to the first image in the sequence as the “previous” image and the second one as the "current" image. Getting the effect down is relatively easy as long as we know the dimensions and position of the previous image in the transition. We can animate the current image by transforming it as per previous image.

The formula that I’m using is transform: translate(x, y) scale(n), where n is equal to the size of previous image divided by the size of current image. Note that we can use a static value of n since the dimensions are fixed for all the images. For example, the image size in the Artists view is 190x190 and 240x240 in the Tracks view. Thus, we can replace n by 190/240 = 0.791. That means the transform value becomes translate(x, y) scale(0.791) in our equation.

Animating from Artists to Tracks

Next thing is to find x and y. We can get these values though click event in the Artists view as:

const {x, y} = event.target.getBoundingClientRect()

...and then send these values to the Tracks view, all while switching the route. Since we aren’t using any state management library, the two components will communicate via their parent component, which is the top level component, App.vue. In App.vue, let’s create a method that switches the route and sends the image info as params.

gotoTracks(position, artistId) { this.$router.push({ name: 'tracks', params: { id: artistId, position: position } }) }

Here’s the relevant code from the repo to reference, in case you’re interested.

Since we have received the position and ID of the image in Tracks, we have all the required data to show and animate it. We’ll first fetch artist information (specifically the name and image URL) using artist ID.

To animate the image, we need to calculate the transform value from the image’s starting position. To set the transform value, I’m using CSS custom properties, which can be done with CSS-in-JS techniques as well. Note that the image’s position that we received through props will be relative to window. Therefore we’ll have to subtract some fixed offset caused by the padding of the container <div> to even out our math.

const { x, y } = this.$route.params.position // padding-left const offsetLeft = 100 // padding-top const offsetTop = 30 // Set CSS custom property value document.documentElement.style.setProperty( '--translate', `translate(${x - offsetLeft}px, ${y - offsetTop}px) scale(0.792)` )

We’ll use this value to create a keyframe animation to move the image:

@keyframes move-image { from { transform: var(--translate); } }

This gets assigned to the CSS animation:

.image { animation: move-image 0.6s; }

...and it will animate the image from this transform value to its original position on component load.

Transitioning from Artists to Tracks

We can use the same technique when going the opposite direction, Tracks to Artists. As we already have the clicked image’s position stored in the parent component, we can pass it to props for Artists as well.

Transitioning from Tracks to Artists Step 5: Show the tracks!

It’s great that we can now move between our two views seamlessly, but the Tracks view is pretty sparse at the moment. So let’s add the track list for the selected artist.

We’ll create an empty white box and a new keyframe to slide it upwards on page load. Then we’ll add three subsections to it: Recent Tracks, Popular Tracks, and Playlist. Again, if you want to jump ahead, feel free to either reference or copy the final code from the repo.

The Tracks view with content

Recent Tracks is the row of thumbnails just below the artist image where each thumbnail includes the track name and track length below it. Since we’re covering animations here, we’ll create a scale-up animation, where the image starts invisible (opacity: 0) and a little smaller than it’s natural size (scale(0.7)), then is revealed (opacity: 1 )and scales up to its natural size (transform: none).

.track { opacity: 0; transform: scale(0.7); animation: scale-up 1s ease forwards; } @keyframes scale-up { to { opacity: 1; transform: none; } }

The Popular Tracks list and Playlist sit side-by-side below the Recent Tracks, where Popular tracks takes up most of the space. We can slide them up a bit on initial view with another set of keyframes:

.track { ... animation: slide-up 1.5s; } @keyframes slide-up { from { transform: translateY(140px); } }

To make the animation feel more natural, we’ll create a stagger effect by adding an incremental animation delay to each item.

@for $i from 1 to 5 { &:nth-child(#{$i + 1}) { animation-delay: #{$i * 0.05}s; } }

The code above is basically looking for each child element, then adding a 0.05 second delay to each element it finds. So, for example, the first child gets a 0.05 second delay, the second child gets a 0.10 second delay and so on.

Check out how nice and natural this all looks:

Bonus: micro-interactions!

One of the fun things about working with animations is thinking through the small details because they’re what tie things together and add delight to the user experience. We call these micro-interactions and they serve a good purpose by providing visual feedback when an action is performed.

Depending on the complexity of the animations, we might need a library like anime.js or GSAP. This example is pretty straightforward, so we can accomplish everything we need by writing some CSS.

First micro-interaction: The volume icon

Let’s first get a volume icon in SVG format (Noun Project and Material Design are good sources). On click, we’ll animate-in and out its path element to show the level of volume. For this, we’ll create a method which switches its CSS class according to the volume level.

<svg @click="changeVolume"> <g :class="`level-${volumeLevel}`"> <path d="..."/> <!-- volume level 1 --> <path d="..."/> <!-- volume level 2 --> <path d="..."/> <!-- volume level 3 --> <polygon points="..."/> </g> </svg>

Based on this class, we can show and hide certain path elements as:

path { opacity: 0; transform-origin: left; transform: translateX(-5px) scale(0.6); transition: transform 0.25s, opacity 0.2s; } .level-1 path:first-child, .level-2 path:first-child, .level-2 path:nth-child(2), .level-3 path { opacity: 1; transform: none; } The animated volume control Second micro-interaction: The favorite icon

Do you like it when you click on Twitter’s heart button? That’s because it feels unique and special by the way it animates on click. We’ll make something similar but real quick. For this, we first get an SVG heart icon and add it to the the markup. Then we’ll add a bouncy animation to it that’s triggered on click.

@keyframes bounce { 0%, 100% { transform: none; } 30% { transform: scale(1.3); } 60% { transform: scale(0.9); } }

Another fun thing we can do is add other small heart icons around it with random sizes and positions. Ideally, we’d add a few absolute-positioned HTML elements that a heart as the background. Let’s Arrange each of them as below by setting their left and bottom values.

We’ll also include a fade away effect so the icons appear to dissolve as they move upward by adding a keyframe animation on the same click event.

@keyframes float-upwards { 0%, 100% { opacity: 0; } 50% { opacity: 0.7; } 50%, 100% { transform: translate(-1px, -5px); } } The animated favorite button Summing up

That’s all! I hope you find all this motivating to try animations on your own websites and projects.

While writing this, I also wanted to expand on the fundamental animation principles we glossed over earlier because I believe that they help choose animation durations, and avoid non-meaningful animations. That’s important to discuss because doing animations correctly is better than doing them at all. But this sounds like a whole another topic to be covered in a future article.

The post Writing Animations That Bring Your Site to Life appeared first on CSS-Tricks.

Blobs!

Css Tricks - Thu, 02/21/2019 - 12:01pm

I was recently a guest editor for an issue of Bizarro Devs. It's a great newsletter! Go sign up! I put in a bunch of links around blobs. Like those weird squishy random shapes that are so "in" right now. Here are those links as well. I'm always a fan of publishing stuff I write ;)

Blobs! Blobs are in! Blobs are — ahem — a bit bizarre. I'll bask in a design like this annual report cover by Matt Pamer all day. I enjoy watching a design trend like this manifest itself in design tooling and become applied in lots of creative and crafty different ways.

We could start with <svg> and draw our own blob using the Pen tool that is pretty much stock in every vector design application. I'm a cheater though, and would probably wind up checking The Noun Project for some blob examples and steal the SVG from there. But sadly, there isn't much there, at least as far as blobs go.

Thank god for... (wait for it)... THE BLOBMAKER:

Once we have a blob, it's just begging to be moved around. Monica Dinculescu shows how to do just that with pure CSS and liberal use of various CSS transforms in a keyframe animation:

See the Pen
CSS only morphing blob
by Monica Dinculescu (@notwaldorf)
on CodePen.

Or we can use a JavaScript library like KUTE.js to get all morph-y, like Heartbeat has done here:

See the Pen
Morphing shapes with KUTE.js
by Heartbeat.UA (@hbagency)
on CodePen.

A library like Greensock could help moving and morphing the blobs around. Greensock even has a plugin that is probably the most powerful morphing tool out there. This Pen uses Greensock, but adds some native SVG filters so that the blobs squish into each other satisfyingly. We could call it the gooey effect:

See the Pen
SVG blob mask
by ATCOM (@Atcom)
on CodePen.

We've only looked at SVG so far, but don't rule out <canvas>! Liam Egan has make this canvas-based blob downright jiggly:

See the Pen
Blob
by Liam Egan (@shubniggurath)
on CodePen.

Why not add a little physics to the party, like gravity, and let them blobs get squishy that way! Hakim El Hattab got it done here:

See the Pen
Blob
by Hakim El Hattab (@hakimel)
on CodePen.

And blobs don't have to be alone! Blobs that are squished together are like fluid. You might get a kick out of Peeke Kuepers article Simulating blobs of fluid.

The post Blobs! appeared first on CSS-Tricks.

Deliver your best work with the help of monday.com

Css Tricks - Thu, 02/21/2019 - 11:58am

(This is a sponsored post.)

Here's the situation: You've bashed out a complicated design over two weeks of near full-time effort, gotten everything down to the exact spec of the design file, turn it in for stakeholder review and... you're way off scope. Turns out a few folks on the team put their heads together, made some changes, and never sent you an updated comp.

Boo!

The unfortunate truth is that this happens all too often in front-end development, but it's really no one person's fault because it boils down to simple collective miscommunication and a lack of transparency on the team.

Well, that's where a project management platform like monday.com comes into play. Even if you're on a remote team or sitting in an office with cubicle walls up to the ceiling, monday.com bridges gaps and tears down walls that could throw a project off-track. With powerful and intuitive tools, like instant messaging for those ad hoc meetings, file storage for a centralized repository of assets, and an activity dashboard for catching up on the status of a project at a glance, monday.com brings project out into the light so everyone is in the loop and on the same page.

Seriously, you'll wonder what you ever did without monday.com in your life once you've used it. It does everything any other project management tool can do — from task lists and milestones to budgets and human resources — but does one important thing that separates it from the rest: the personal touch that makes everyone on the team feel valuable, included and heard. That's tough to beat and unique to the project management landscape.

Like most things, seeing is believing, so give monday.com a try today. The first 14 days are on the house and will give you a feel for what makes it so great.

Try it Free

Direct Link to ArticlePermalink

The post Deliver your best work with the help of monday.com appeared first on CSS-Tricks.

CSS Variables + calc() + rgb() = Enforcing High Contrast Colors

Css Tricks - Thu, 02/21/2019 - 6:26am

As you may know, the recent updates and additions to CSS are extremely powerful. From Flexbox to Grid, and — what we’re concerned about here — Custom Properties (aka CSS variables), all of which make robust and dynamic layouts and interfaces easier than ever while opening up many other possibilities we used to only dream of.

The other day, I was thinking that there must be a way to use Custom Properties to color an element's background while maintaining a contrast with the foreground color that is high enough (using either white or black) to pass WCAG AA accessibility standards.

It’s astonishingly efficient to do this in JavaScript with a few lines of code:

var rgb = [255, 0, 0]; function setForegroundColor() { var sum = Math.round(((parseInt(rgb[0]) * 299) + (parseInt(rgb[1]) * 587) + (parseInt(rgb[2]) * 114)) / 1000); return (sum > 128) ? 'black' : 'white'; }

This takes the red, green and blue (RGB) values of an element’s background color, multiplies them by some special numbers (299, 587, and 144, respectively), adds them together, then divides the total by 1,000. When that sum is greater than 128, it will return black; otherwise, we’ll get white. Not too bad.

The only problem is, when it comes to recreating this in CSS, we don't have access to a native if statement to evaluate the sum. So,how can we replicate this in CSS without one?

Luckily, like HTML, CSS can be very forgiving. If we pass a value greater than 255 into the RGB function, it will get capped at 255. Same goes for numbers lower than 0. Even negative integers will get capped at 0. So, instead of testing whether our sum is greater or less than 128, we subtract 128 from our sum, giving us either a positive or negative integer. Then, if we multiply it by a large negative value (e.g. -1,000), we end up with either very large positive or negative values that we can then pass into the RGB function. Like I said earlier, this will get capped to the browser’s desired values.

Here is an example using CSS variables:

:root { --red: 28; --green: 150; --blue: 130; --accessible-color: calc( ( ( (var(--red) * 299) + (var(--green) * 587) + (var(--blue) * 114) / 1000 ) - 128 ) * -1000 ); } .button { color: rgb( var(--accessible-color), var(--accessible-color), var(--accessible-color) ); background-color: rgb( var(--red), var(--green), var(--blue) ); }

If my math is correct (and it's very possible that it's not) we get a total of 16,758, which is much greater than 255. Pass this total into the rgb() function for all three values, and the browser will set the text color to white.

At this point, everything seems to be working in both Chrome and Firefox, but Safari is a little cranky and gives a different result. At first, I thought this might be because Safari was not capping the large values I was providing in the function, but after some testing, I found that Safari didn't like the division in my calculation for some reason.

Taking a closer look at the calc() function, I noticed that I could remove the division of 1,000 by increasing the value of 128 to 128,000. Here’s how that looks so far:

:root { --red: 28; --green: 150; --blue: 130; --accessible-color: calc( ( ( (var(--red) * 299) + (var(--green) * 587) + (var(--blue) * 114) ) - 128000 /* HIGHLIGHT */ ) * -1000 ); } .button { color: rgb( var(--accessible-color), var(--accessible-color), var(--accessible-color) ); background-color: rgb( var(--red), var(--green), var(--blue) ); }

Throw in a few range sliders to adjust the color values, and there you have it: a dynamic UI element that can swap text color based on its background-color while maintaining a passing grade with WCAG AA.

See the Pen
CSS Only Accessible Button
by Josh Bader (@joshbader)
on CodePen.

Putting this concept to practical use

Below is a Pen showing how this technique can be used to theme a user interface. I have duplicated and moved the --accessible-color variable into the specific CSS rules that require it, and to help ensure backgrounds remain accessible based on their foregrounds, I have multiplied the --accessible-color variable by -1 in several places. The colors can be changed by using the controls located at the bottom-right. Click the cog/gear icon to access them.

See the Pen
CSS Variable Accessible UI
by Josh Bader (@joshbader)
on CodePen.

There are other ways to do this

A little while back, Facundo Corradini explained how to do something very similar in this post. He uses a slightly different calculation in combination with the hsl function. He also goes into detail about some of the issues he was having while coming up with the concept:

Some hues get really problematic (particularly yellows and cyans), as they are displayed way brighter than others (e.g. reds and blues) despite having the same lightness value. In consequence, some colors are treated as dark and given white text despite being extremely bright.

What in the name of CSS is going on?

He goes on to mention that Edge wasn’t capping his large numbers, and during my testing, I noticed that sometimes it was working and other times it was not. If anyone can pinpoint why this might be, feel free to share in the comments.

Further, Ana Tudor explains how using filter + mix-blend-mode can help contrast text against more complex backgrounds. And, when I say complex, I mean complex. She even goes so far as to demonstrate how text color can change as pieces of the background color change — pretty awesome!

Also, Robin Rendle explains how to use mix-blend-mode along with pseudo elements to automatically reverse text colors based on their background-color.

So, count this as yet another approach to throw into the mix. It’s incredibly awesome that Custom Properties open up these sorts of possibilities for us while allowing us to solve the same problem in a variety of ways.

The post CSS Variables + calc() + rgb() = Enforcing High Contrast Colors appeared first on CSS-Tricks.

Colorful Typographic Experiments

Css Tricks - Wed, 02/20/2019 - 1:05pm

There have been some interesting, boundary-pushing typography-related experiments lately. I was trying to think of a joke like "somethings in the descenders" but I just can't find something that will stand on its own leg without being easy to counter.

Codrin Pavel created a fascinating multi-color typeface called CSSans.

It's not a "font", because a font is a file, like "lato.woff2" or whatever. This is a CSS file, and you write in it like this:

<div class="cssans cssans--center"> <div class="cssans__accessible">Cool News</div> <div class="cssans__word"> <b class="cssans:C"></b> <b class="cssans:o"></b> <b class="cssans:o"></b> <b class="cssans:l"></b> </div> <div class="cssans__word"> <b class="cssans:N"></b> <b class="cssans:e"></b> <b class="cssans:w"></b> <b class="cssans:s"></b> </div> </div>

Note the special <div> at the top with the full word in it, while those empty <b> elements do the actual drawing of the glyphs. I wouldn't call it entirely accessible, as I'd argue part of accessibility is stuff like find-on-page with highlighting and selectable text. But this is obviously an artistic experiment and your implementation could go any number of ways. I'd love to see an attempt at setting transparent SVG <text> over the top of it that is sized the same so that the text is selectable.

Looks like the landing page was built in CodePen Projects!

This technique and its relationship with accessibility is pretty interesting and actually more relevant than you might think. In fact, it looks like Facebook uses a similar span technique to fight ad-blocking.

Harbor Type recently put out Rocher Color, a free color font. Yes, color font. That's a thing. And Rocher Color is actually a color font and a variable font.

Support seems kinda decent to me, but it's complicated because there are a bunch of different kinds all with different support across browsers.

The other story is that they are, well, kinda humongous, size-wise. The woff2 file is probably the most relevant here as it's such a modern feature anyway. The download from the site (RocherColorGX.woff2) clocks in at 178KB. Not something you'd just toss on a page for a single headline probably, considering it's not just weight with fonts — but you're also always fighting the FOUT/FOIT battle.

I think to justify using a beefy color font like this you'd...

  1. Use it quite a bit around the site for dynamic headlines
  2. Customize the colors to be perfect for you (ahead of time)
  3. Make use of the fancy variable font features like the bevel and shadow adjustments (on the fly)

If you don't see yourself doing those things, you might be better off using <svg> with these shapes all expanded out to paths. You could still use this font to make the SVG, assuming your design tool supports this kind of font. You won't get text wrapping or anything, but the file size and loading speed will be much faster. Or you could even use a graphic format like PNG/WebP, and there's no terrible shame in that if you still use a semantic element for the headline (visually hidden, of course). You won't get find-on-page highlighting or select-ability, but might be an OK trade-off for a one-off.

Kenneth Ormandy has rounded up some more interesting typographic experiments in CSS. In his post, he mentions Diana Smith's Pure CSS Font, which builds itself from empty elements and all kinds of fancy CSS trickery to draw the shapes.

The point of this project is right in the header:

For private, SEO-hidden, CAPTCHA-friendly unselectable text. Deter plagiarism and spambots!

Hidden for assistive technology too, so careful there, but it seems to me this project is more about exploring possibilities. After all, it's the letters that power Diana's remarkable CSS paintings like Zigaro.

Don't miss Kenneth's post, as he links to lots more fascinating examples of people being typographers with very unconventional tools. Kenneth takes a crack himself with this fascinating little experiment, using a button there to expose the tricks within:

See the Pen
START Pure CSS Lettering test 1
by Kenneth Ormandy (@kennethormandy)
on CodePen.

The post Colorful Typographic Experiments appeared first on CSS-Tricks.

<span>L</span><span>e</span><span>t</span><span>t</span><span>e</span><span>r</span><span>s</span>

Css Tricks - Wed, 02/20/2019 - 11:05am

Did you see this Facebook crap?

"Why do I need a 4Ghz quadcore to run facebook?" This is why. A single word split up into 11 HTML DOM elements to avoid adblockers. pic.twitter.com/Zv4RfInrL0

— Mike Pan (@themikepan) February 6, 2019

I popped over to Facebook to verify that and what I saw was a different and even more nested mess:

They are trying to fight your ad blocker browser extension. Of course they are. I'm sure at their scale not doing this means losing millions of dollars. But I wonder if it's really losing money when you factor in losing trust, and potentially losing people on the platform entirely.

It just feels so rude, doesn't it? Like a user specifically installs technology onto their computer in order to exert some control over what they allow onto their computers and into their eyeballs. And they are saying, "No, we do not respect that choice. We are going to fight your technology with our technology and force feed this stuff onto your computer and your eyeballs." Doesn't sit right.

I'm not unaware that ad blockers have ad adverse effect on the ability for websites to make money. That's quite literally how I make money. But I don't want to do it fighting and at the expense of breaking trust. I want to do it gracefully while building trust.

Anyway.

I wonder what writing HTML to help ad blockers would look like instead:

<!-- start: advertisement --> <div class="ad sponsor paid" id="ad-1" data-ad="true"> <div>Sponsor:</div> <a href="https://sponsor.com" rel="nofollow">Company</span> </div> <!-- end: advertisement -->

The good ones have been doing it for ages.

This span-based lettering stuff makes me think of libraries like Splitting.js and Lettering.js that break up text into individual <span>s for styling reasons.

Turns out that doesn't affect on-page search (i.e. if you search for "dog," you'll find <span>d</span><span>o</span><span>g</span>), but it does affect some screen readers in that they will treat each letter distinctly, which can result in pretty awful audio output, like pauses between letters where you wouldn't expect or want them.

It's totally solvable though!

I just read about how powerful aria-label is via Web Platform News, quoting Amelia Bellamy-Royds:

An aria-label attribute on a button or link effectively replaces the text content of that element with the new label.

It was cool to see that's what Lettering.js does by default! And Splitting.js is figuring out the best method for them, which involves aria-label.

Oh, and as ever, ::nth-letter() would be cool. 2018 recap of a 2011 request.

The post <span>L</span><span>e</span><span>t</span><span>t</span><span>e</span><span>r</span><span>s</span> appeared first on CSS-Tricks.

Diana Smith’s Top 5 CSS Properties She Uses to Produce CSS Art

Css Tricks - Wed, 02/20/2019 - 11:04am

Have you seen Diana Smith's CSS drawings? Stunning. These far transcend the CSS drawings that sort of crudely replicate a flat SVG scene, like I might attempt. We were lucky enough for her to post some of her CSS drawing techniques here last year.

Well, Diana has also listed the top five CSS properties she uses to get these masterpieces done, and they are surprising in their plainness:

  1. border-radius
  2. box-shadow
  3. transform
  4. gradients
  5. overflow

...but of course, layered in trickery!

... for custom rounded elements that are meant to mimic organic objects like faces, it is imperative that you become intimately familiar with all eight available parameters in the border-radius property.

Diana shows her famous Francine drawing with each of the most used properties turned off:

Without border-radius Without transform

Be sure to check out this VICE interview she did as well. She covers gems like the fact that Francine was inspired by American Dad (lol) and that the cross-browser fallbacks are both a fascinating and interesting mess.

Direct Link to ArticlePermalink

The post Diana Smith’s Top 5 CSS Properties She Uses to Produce CSS Art appeared first on CSS-Tricks.

Social Cards as a Service

Css Tricks - Tue, 02/19/2019 - 5:19am

I love the idea of programmatically generated images. That power is close at hand these days for us front-end developers, thanks to the concept of headless browsers. Take Puppeteer, the library for controlling headless Chrome. Generating images from URLs is their default use case:

const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://example.com'); await page.screenshot({path: 'example.png'}); await browser.close(); })();

That ought to get the ol' mind grape going. What if we had URLs on our site that — with the power of our HTML and CSS skills — created perfect little designs for sharing using dynamic data... then turned them into images and used them for our meta tags?

The first I saw of this idea was Drew McLellan's Dynamic Social Sharing Images. Drew wrote a script to fire up Puppeteer and get the job done.

Since the design part is entirely an HTML/CSS adventure, I'm sure you could imagine a setup where the URL passed in parameters that did things like set copy and typography, colors, sizes, etc. Zeit built exactly that!

The URL is like this:

https://og-image.now.sh/I%20am%20Chris%20and%20I%20am%20**cool**%20la%20tee%20ding%20dong%20da..png?theme=light&md=1&fontSize=100px&images=https%3A%2F%2Fassets.zeit.co%2Fimage%2Fupload%2Ffront%2Fassets%2Fdesign%2Fhyper-color-logo.svg

Kind of amazing that you can spin up an entire browser in a cloud function! Netlify also offers cloud functions, and when I mentioned this to Phil Hawksworth, he told me he was already doing this for his blog!

So on a blog post like this one, an image like this is automatically generated:

Which is inserted as meta:

<meta property="og:image" content="https://www.hawksworx.com/card-image/-blog-find-that-at-card.png">

I dug through Phil's repos, naturally, and found his little machine for doing it.

I'm madly envious of all this and need to get one set up for myself.

The post Social Cards as a Service appeared first on CSS-Tricks.

Don’t Get Clever with Login Forms

Css Tricks - Tue, 02/19/2019 - 5:18am

Brad points out some UX problems with a variety of apps that are doing things a little outside of the norm when it comes to their login forms. There is already a bunch of things to get right with forms to begin with (e.g. use the right input types, label your inputs, don't have whack password requirements, use SSL, etc.)... OMG why complicate it even more?!

A "password manager test" should be a development best practice here. Does it work cleanly with the built-in browser password manager? How about 1Password and LastPass? No? Give it some love, please and thank you.

Direct Link to ArticlePermalink

The post Don’t Get Clever with Login Forms appeared first on CSS-Tricks.

How @supports Works

Css Tricks - Mon, 02/18/2019 - 7:39am

CSS has a neat feature that allows us to test if the browser supports a particular property or property:value combination before applying a block of styles — like how a @media query matches when, say, the width of the browser window is narrower than some specified size and then the CSS within it takes effect. In the same spirit, the CSS inside this feature will take effect when the property:value pair being tested is supported in the current browser. That feature is called @supports and it looks like this:

@supports (display: grid) { .main { display: grid; } }

Why? Well, that's a bit tricky. Personally, I find don't need it all that regularly. CSS has natural fallback mechanisms such that if the browser doesn't understand a property:value combination, then it will ignore it and use something declared before it if there is anything, thanks to the cascade. Sometimes that can be used to deal with fallbacks and the end result is a bit less verbose. I'm certainly not a it's-gotta-be-the-same-in-every-browser kinda guy, but I'm also not a write-elaborate-fallbacks-to-get-close kinda guy either. I generally prefer a situation where a natural failure of a property:value doesn't do anything drastic to destroy functionality.

That said, @supports certainly has use cases! And as I found out while putting this post together, plenty of people use it for plenty of interesting situations.

A classic use case

The example I used in the intro is a classic one that you'll see used in lots of writing about this topic. Here it is a bit more fleshed out:

/* We're gonna write a fallback up here in a minute */ @supports (display: grid) { .photo-layout { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-gap: 2rem; } }

Nice grid! Repeating and auto-filling columns is a sweet feature of CSS grid. But, of course, there are browsers that don't support grid, or don't support all the specific features of it that I'm using above there.

For example, iOS shipped support for CSS grid in version 10.2, but iOS has had flexbox support since version 7. That's a decent gap of people with older iOS devices that do support flexbox but not grid. I'm sure there are more example gaps like that, but you probably get the idea.

I was running on an older version of mobile safari and many many many many many sites were flat out broken that used grid

I’m waiting another year or so before messing about with it

— David Wells (@DavidWells) February 6, 2019

It may be acceptable to let the fallback for this be nothing, depending on the requirements. For example, vertically stacked block-level elements rather than a multi-column grid layout. That's often fine with me. But let's say it's not fine, like a photo gallery or something that absolutely needs to have some basic grid-like structure. In that case, starting with flexbox as the default and using @supports to apply grid features where they're supported may work better...

.photo-layout { display: flex; flex-wrap: wrap; > div { flex: 200px; margin: 1rem; } } @supports (display: grid) { .photo-layout { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-gap: 2rem; > div { margin: 0; } } }

The "fallback" is the code outside of the @supports block (the properties above the block in the example above), and the grid code is either inside or after. The @supports block doesn't change any specificity, so we need the source order to help make sure the overrides work.

Notice I had to reset the margin on the divs inside the @supports block. That's the kind of thing I find a bit annoying. There is just enough crossover between the two scenarios that it requires being super aware of how they impact each other.

Doesn't that make you wish it could be entirely logically separated...

There is "not" logic in @supports blocks, but that doesn't mean it should always be used

Jen Simmons put this example in an article called Using Feature Queries in CSS a few years ago:

/* Considered a BAD PRACTICE, at least if you're supporting IE 11 and iOS 8 and older */ @supports not (display: grid) { /* Isolated code for non-support of grid */ } @supports (display: grid) { /* Isolated code for support of grid */ }

Notice the not operator in the first block. That's checking for browsers that do not support grid in order to apply certain styles to those browsers. The reason this approach is considered bad practice is that the browser support for @supports itself has to be considered!. That's what makes this so dang tricky.

It's very appealing to write code in logically separated @supports blocks like that because then it's starting from scratch each time and doesn't need to be overriding previous values and dealing with those logical mind-benders. But let's go back to the same iOS situation we considered before... @supports shipped in iOS in version 9 (right between when flexbox shipped in iOS 7 and grid shipped in iOS 10.2). That means any flexbox fallback code in a @supports block using the not operator to check for (display: grid) {} support wouldn't work in either iOS 7 or 8, meaning the fallback now needs a fallback from working in browsers it otherwise would have. Phew!

The big reason to reach for @supports is to account for very different implementations of something depending on feature support where it becomes easier to reason and distinguish between those implementations if the blocks of code are separated.

We'll probably get to a point where we can use mutually-exclusive blocks like that without worry. Speaking of which...

@supports is likely to be more useful over time.

Once @supports is supported in all browsers you need to support, then it's good to start using it more aggressively and without having to factor in the complication of considering whether @supports itself is supported. Here's the support grid on that:

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

DesktopChromeOperaFirefoxIEEdgeSafari2812.122No129Mobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox9.0-9.246all4.47164

Basically, IE 11 and any iOS device stuck on iOS 8 are the pain points. If your requirements are already past those, then you're good to use @supports more freely.

The irony is that there hasn't been a ton of CSS features shipping that have big clear @supports use cases — but there are some! Apparently, it's possible to test new fancy stuff like Houdini:

Using it on my wedding website to check for Houdini support &#x1f3a9;&#x1f430;

— Sam Richard (@Snugug) February 6, 2019

(I'm not sure entirely what you'd put in the @supports block to do that. Has anyone else done this?)

When @supports isn't doing anything useful

I've seen a good amount of @supports uses in the wild where the end result is exactly as it would be without using it. For example...

@supports (transform: rotate(5deg)) { .avatar { transform: rotate(5deg); } }

On some level, that makes perfect logical sense. If transforms are supported, use them. But it's unnecessary if nothing different is happening in a non-support scenario. In this case, the transform can fail without the @supports block and the result is the same.

Here's another example of that shaking out.

There are browser extensions for playing with @supports

There are two of them!

They are both centered around the idea that we can write @supports blocks in CSS and then toggle them on and off as if we're looking at a rendering of the code in a browser that does or doesn't support that feature.

Here's a video of Keith's tool applied to the scenario using grid with a flexbox fallback:

This is fun to play with and is very neat tech. But in this exact scenario, if I was able to pull off the layout identically with flexbox, then I'd probably just do that and save that little bit of technical debt.

Ire's tool, which she wrote about in the article Creating The Feature Queries Manager DevTools Extension, has a slightly different approach in that it shows the feature queries that you actually wrote in your CSS and provides toggles to flip them on and off. I don't think it works through iframes though, so I popped open Debug Mode to use it on CodePen.

More real world use cases for @supports

Here's one from Erik Vorhes. He's styling some custom checkboxes and radio buttons here, but wraps all of it in a @supports block. None of the styling gets applied unless the block passes the support check.

@supports (transform: rotate(1turn)) and (opacity: 0) { /* all the styling for Erik's custom checkboxes and radio buttons */ }

Here are several more I've come across:

  • Joe Wright and Tiago Nunes mentioned using it for position: sticky;. I'd love to see a demo here! As in, where you go for position: sticky;, but then have to do something different besides let it fail for a non-supporting browser.
  • Keith Grant and Matthias Ott mention using it for object-fit: contain;. Matthias has a demo where positioning trickery is used to make an image sort of fill a container, which is then made easier and better through that property when it's available.
  • Ryan Filler mentions using it for mix-blend-mode. His example sets more opacity on an element, but if mix-blend-mode is supported, it uses a bit less and that property which can have the effect of seeing through an element on its own.
  • .thing { opacity: 0.5; } @supports (mix-blend-mode: multiply) { .thing { mix-blend-mode: multiply; opacity: 0.75; } }
  • Rik Schennink mentioned the backdrop-filter property. He says, "when it's supported the opacity of the background color often needs some fine tuning."
  • Nour Saud mentioned it can be used to detect Edge through a specific vendor-prefixed property: @supports (-ms-ime-align:auto) { }.
  • Amber Weinberg mentioned using it for clip-path because adjusting the sizing or padding of an element will accommodate when clipping is unavailable.
  • Ralph Holzmann mentioned using it to test for that "notch" stuff (environment variables).
  • Stacy Kvernmo mentioned using it for the variety of properties needed for drop capping characters. Jen Simmons mentions this use case in her article as well. There is an initial-letter CSS property that's pretty fantastic for drop caps, but is used in conjunction with other properties that you may not want to apply at all if initial-letter isn't supported (or if there's a totally different fallback scenario).

Here's a bonus one from Nick Colley that's not @supports, but @media instead! The spirit is the same. It can prevent that "stuck" hover state on touch devices like this:

@media (hover: hover) { a:hover { background: yellow; } } Logic in @supports

Basic:

@supports (initial-letter: 4) { }

Not:

@supports not (initial-letter: 4) { }

And:

@supports (initial-letter: 4) and (transform: scale(2)) { }

Or:

@supports (initial-letter: 4) or (-webkit-initial-letter: 4) { }

Combos:

@supports ((display: -webkit-flex) or (display: -moz-flex) or (display: flex)) and (-webkit-appearance: caret) { } JavaScript Variant

JavaScript has an API for this. To test if it exists...

if (window.CSS && window.CSS.supports) { // Apparently old Opera had a weird implementation, so you could also do: // !!((window.CSS && window.CSS.supports) || window.supportsCSS || false) }

To use it, either pass the property to it in one param and the value in another:

const supportsGrid = CSS.supports("display", "grid");

...or give it all in one string mirroring the CSS syntax:

const supportsGrid = CSS.supports("(display: grid)"); Selector testing

At the time of this writing, only Firefox supports this sort of testing (behind an experimental flag), but there is a way to test the support of selectors with @supports. MDN's demo:

@supports selector(A > B) { } You?

Of course, we'd love to see Pens of @supports use cases in the comments. So share 'em!

The post How @supports Works appeared first on CSS-Tricks.

instant.page

Css Tricks - Mon, 02/18/2019 - 7:25am

instant.page is a pretty cool project from Alexandre Dieulot. Alexandre has been at this idea for half a decade now, as InstantClick is his and is essentially the same exact idea.

The idea is that there is a significant delay between hovering over a link and clicking that link. Say it takes you 300ms of delay. That 300ms could have been spent preloading the next page. And if you do use that time preloading, that page loads that much faster.

This new project makes use of newer tech to get it done. It's hardly any code., the core of which is appending a <link rel="prefetch" href=""> to the document of the link you're about to click/touch.

The page encourages you to hotlink the script, which means possible cache-hits in case you've already visited a page using this. It's not risky in the way other third-party JavaScript can be because the integrity attribute means that if you trust the code as it is now, it can't ever change unless you change that attribute along with it. It also cleverly uses the type="module" to prevent it from loading anything in browsers that don't support prefetching anyway.

Still, you could self-host it if you wanted. I have no idea who's ponying up the for the bandwidth here, so another risk is a hung script should it stop responding one day.

You could argue that it doesn't do the prefetching as absolutely responsibly as it could. Google's similar quick link library (which we covered here) does two interesting things in which to attempt to be more responsible with prefetching: 1) wait for requestIdleCallback and 2) respects info from navigator.connection, like a user enabling data-saver mode.

Direct Link to ArticlePermalink

The post instant.page appeared first on CSS-Tricks.

IE10-Compatible Grid Auto-Placement with Flexbox

Css Tricks - Mon, 02/18/2019 - 6:15am

If you work on web applications that support older browsers, and have lusted after CSS Grid from the sidelines like I have, I have some good news: I've discovered a clever CSS-only way to use grid auto-placement in IE10+!

Now, it's not actually CSS Grid, but without looking at the code itself, you wouldn't be able to tell. The HTML structure looks like CSS Grid. It has a defined set of columns with an undefined amount of rows and it has gutters that support borders and shadows on the cells without hacks. But what’s actually happening behind the scenes is a combination of flexbox and margins.

In this article, I'll walk through the approach. Here’s a demo of what we’re looking at:

See the Pen
IE10-compatible CSS-Grid-like column layout
by Brian Holt (@bholtbholt)
on CodePen.

Auto-flowing rows with flexbox wrap Flexbox-created auto-placement grid

Getting the basic grid setup is very simple. If you're at all familiar with flexbox, I'm certain you've already guessed flex-wrap: wrap is the trick here. And you'd be right.

Let's get the HTML markup in place before we write any CSS. We want it to resemble the same structure as if we were using auto-placement — a .grid container and an undefined number of .grid__cells.

<div class="grid"> <div class="grid__cell">...</div> ... </div>

We set three grid breakpoints. A single-column, two-column, and three-column layout for mobile-devices, small screens, and medium screens, respectively. I'm using the breakpoints used in Bootstrap for this article, though we’d want to define them at actual points where the layout breaks if we were working with real content.

$screen-sm-min: 768px; $screen-sm-max: 991px; $screen-md-min: 992px; Mobile-first grid collapses into a single column

A mobile-first approach means our single-column layout is already complete since each .grid__cell is already a block. We set .grid to become a flexbox container after the first breakpoint, and wrap cells.

@media (min-width: $screen-sm-min) { .grid { display: flex; flex-wrap: wrap; } }

Our two- and three-column layouts need explicit widths and flex properties; otherwise they'll cram onto a single line. While testing IE10, I experienced unexpected behavior with the flex-basis property, and found setting an explicit width with flex-basis: auto was more consistent. This didn't seem to be a problem with IE11 though.

.grid__cell { min-width: 0; flex: 1 1 auto; } // Two-column grid @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) { $width: 50%; .grid__cell { width: $width; } } // Three-column grid @media (min-width: $screen-md-min) { $width: 33.33%; .grid__cell { width: $width; } }

We don't need to wrap .grid__cell in a media query since its flex properties won't have the effect when the parent isn't a flexbox container. We also define an upper-limit to the two-column media query so it doesn't affect the three-column grid.

And that's it! We now have a responsive, fluid, wrapping flexbox grid. The easy part is done… well, as long as we only ever have items that are multiples of two and three. With flex: 1 1 auto, the last item will always take up any remaining space in the last row.

Two-column grid on smaller screens Three-column grid on large screens Aligning cells in the last row

The elusive last row is why we're here, right? By default, each cell will stretch to the end of the row in a flexbox layout, but grid leaves a blank spot. How do we do that in flexbox? With pseudo-elements!

The trick is to add a pseudo-element to the .grid container and set it like a cell. We define the :after pseudo-element cell at each of our breakpoints with the same width as a real cell.

@media (min-width: $screen-sm-min) { .grid { ... &:after { content: ''; display: block; flex: 1 1 auto; } } } @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) { $width: 50%; .grid:after { width: $width; } } @media (min-width: $screen-md-min) { $width: 33.33%; .grid:after { width: $width; } }

This creates a fake cell that will push against our real cells and align our two-column grid when the cells are odd. Leaving its height undefined allows it to collapse to nothing when the cells are even.

Two-column grid with odd cells, snapping into place

Our three-column grid is a bit more complex because we need to handle multiple states, like when there is one empty cell and when there are two empty cells.

Three-column grid with one empty cell

Our one empty cell state is already handled because it isn't really any different from one empty cell in two columns. The :after cell has its width set and completes the row. The story changes when there are two empty cells though because flex: 1 1 auto rears its head again: the last cell now stretches across 50% of the width when pushed against the pseudo-element.

Three-column grid with two empty cells

Using CSS :nth-of-type selectors, we can target the first column in each row. Since our rows are multiples of three, we target them with 3n then count backwards by 2 to get the first element in each row.

@media (min-width: $screen-md-min) { .grid__cell { ... &:nth-of-type(3n-2) { background-color: red; } } } Targeting the first cell in each three-column row

We're broadly targeting all the cells in the first column, but we need to limit the selection to only the last row. Actually, we need to limit it to when it's the last cell in the first column of the last row. Luckily, there's a handy pseudo-selector for targeting the last item of its kind. We chain :last-of-type to create the logical statement.

@media (min-width: $screen-md-min) { .grid__cell { ... &:nth-of-type(3n-2):last-of-type { background-color: red; } } }

Now that we have the last cell in the first column of the last row selected, we use a margin to push the :after cell to the last column and fill the middle cell.

@media (min-width: $screen-md-min) { .grid__cell { ... &:nth-of-type(3n-2):last-of-type { margin-right: $width; } } }

Here's our flexbox-defined-auto-placement-grid-imitator in full. Look at its beautifully lined up rows. I bet you can't even tell it's not CSS Grid!

Our complete three-column grid. Adding gutters with margins

CSS Grid's spec has a column and row gap to provide space between each cell. Creating gutters in flexbox is much more challenging. It looks like it's coming to flexbox, but we're not there yet…and IE will never be.

In Daniel Tonon’s guide on CSS Grid in IE, he used an inner-cell div with negative margins, borders, a bit of padding, and overflow: hidden. While maybe a bit hacky, the effect works, but it breaks our desire to maintain CSS Grid-like HTML structure. The approach I prefer might feel a bit crude, but I also found it the easiest to read and understand. Further, it continues using :nth-of-type pseudo-selectors which makes the overall approach feel consistent.

We want gaps between the cells, but not around the outside. We also want our cells to sit flush with the container.

Gaps between the cells, not on the outside.

Our mobile or single-column grid only needs a bottom margin on the cells. We add that and override the very last cell with margin-bottom: 0 so the cell fits flush against the container. Normally I'd use initial, but there's no support in IE.

$col-gap: 16px; .grid__cell { ... margin-bottom: $col-gap; &:last-of-type { margin-bottom: 0; } } Single-column grid with gaps between each row

Our two- and three-column grids need margins on the right of the cells, no right margins in the last column, and no bottom margins on any of the last row's cells. Because of the margins, we'll also need to recalculate our widths since the cells will wrap if they don't fit.

In a two-column layout, getting the right (or second) column is fairly easy with :nth-of-type(2n) or :nth-of-type(even). I prefer an n-multiplier for consistency with our three-column grid and for calculating the last row.

Our last row is a bit more tricky. When we have odd cells our mobile-first CSS takes care of removing the bottom margins since the cell is the :last-of-type and our :after cell doesn't have margins applied.

Two-columns with even cells

When we have even cells we need to target the second last cell, but only when it is in the first column position. If we didn't qualify it, the second last cell will grow vertically with to match the height of the second last row. We can target it with :nth-of-type(2n-1):nth-last-of-type(2).

@media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) { $width: calc(50% - #{$col-gap}); .grid__cell { ... margin-right: $col-gap; // Remove margin in last column &:nth-of-type(2n) { margin-right: 0; } // For when the last row is complete // . . // * . &:nth-of-type(2n-1):nth-last-of-type(2) { margin-bottom: 0; } } } Two-columns with even cells that sit flush against the container

Our three-column gutters take the same approach. We add margin-right to all of them, remove it from the third column, and remove bottom margins from the last row. Again our last cell is handled by our mobile-first approach, but now we need to cover when there are two cells in the last row and when when there are three cells. We can qualify our selectors with nth-of-type and nth-last-of-type.

@media (min-width: $screen-md-min) { $width: calc(33% - #{$col-gap}); .grid__cell { ... margin-right: $col-gap; // Remove margin in last column &:nth-of-type(3n) { margin-right: 0; } // For when there two items in the last row // . . . // * . &:nth-of-type(3n-2):nth-last-of-type(2) { margin-bottom: 0; } // For when the last row is complete // . . . // * * . &:nth-of-type(3n-1):nth-last-of-type(2), &:nth-of-type(3n-2):nth-last-of-type(3) { margin-bottom: 0; } } } Three-column grid with gutters and an empty cell

We need to adjust the margin of last cell in the last row when it's alone because of the columns. We use 33% plus a gutter on each side.

@media (min-width: $screen-md-min) { $width: calc(33% - #{$col-gap}); .grid__cell { ... // When there is only one item in the last rpw // Fill the margin so it's like the last item is // double the width // . . . // *-> &:nth-of-type(3n-2):last-of-type { margin-right: calc(33% + #{$col-gap * 2}); } } }

Now our gutters are installed and the grid is complete! Fill them borders, shadows, or whatever your heart desires.

Complete three-column grid with gutters using flexbox. Wrapping up

Here’s the final result one more time:

See the Pen
IE10-compatible CSS-Grid-like column layout
by Brian Holt (@bholtbholt)
on CodePen.

I believe this technique could also support IE9 with minor adjustments, like using inline-blocks instead of flexbox. We could also expand to a four-column grid by adding another breakpoint and using the same approach as the three-column grid. Feel free to use this approach and I hope it helps!

The post IE10-Compatible Grid Auto-Placement with Flexbox appeared first on CSS-Tricks.

The Magic of React-Based Multi-Step Forms

Css Tricks - Fri, 02/15/2019 - 5:20am

One way to deal with long, complex forms is to break them up into multiple steps. You know, answer one set of questions, move on to another, then maybe another, and so on and so forth. We often refer to these as multi-step forms (for obvious reasons), but others also take to calling it a “wizard” form.

Multi-step forms can be a great idea! By only showing a few inputs on a screen at a time, the form may feel more digestible and prevent users from feeling overwhelmed by a sea of form fields. Although I haven’t looked it up, I’m willing to say no one enjoys completing a ginormous form — that’s where multiple steps can come in handy.

The problem is that multi-step forms — while reducing perceived complexity on the front end — can feel complex and overwhelming to develop. But, I’m here to tell you that it’s not only achievable, but relatively straightforward using React as the base. So, that’s what we’re going to build together today!

Here’s the final product:

See the Pen
React Simple Wizard Form
by Nathan Sebhastian (@nathansebhastian)
on CodePen.

Let’s build it!

The easiest way to create a multi-step form is to create a container form element that contains all the steps inside of it as components. Here’s a visual showing that container (<MasterForm/>), the components inside of it (<Step1/>, <Step2/>, <Step3/>) and the way states and props are passed between them.

<MasterForm/> serves as the container while three child components inside of it act as each step of the form.

Although it seems to be more complex than a regular form, a multi-step form still uses the same principles as a React form:

  • State is used for storing data and user inputs.
  • Component is used for writing methods and the interface.
  • Props are used for passing data and function into elements.

Instead of having one form component, we will have one parent component and three child components. In the diagram above, <MasterForm/> will send data and functions to the child components via props, and in turn, the child components will trigger a handleChange() function to set values in the state of <MasterForm/>. It’s one big happy family over here!

We'll need a function to move the form from one step to another as well, and we’ll get to that a little later.

The step child (get it?) components will receive props from the <MasterForm/> parent component for value and onChange props.

  • <Step1/> component will render an email address input
  • <Step2/> will render a username input
  • <Step3/> will render a password input and a submit button

<MasterForm/> will supply both data and function into child components, and child components will pass user inputs back to the parent using its props.

Creating the step (child) components

First, we’ll create the form’s child components. We’re keeping things pretty barebones for this example by only using one input per step, but each step could really be as complex as we’d like. Since the child components look almost similar between one another, I’m just gonna show one of them here. But be sure to take a look at the demo for the full code.

class Step1 extends React.Component { render() { if (this.props.currentStep !== 1) { // Prop: The current step return null } // The markup for the Step 1 UI return( <div className="form-group"> <label htmlFor="email">Email address</label> <input className="form-control" id="email" name="email" type="text" placeholder="Enter email" value={this.props.email} // Prop: The email input data onChange={this.props.handleChange} // Prop: Puts data into state /> </div> ) } }

Now we can put this child component into the form’s render() function and pass in the necessary props. Just like in React’s form documentation, we can still use handleChange() to put the user’s submitted data into state with setState(). A handleSubmit() function will run on form submit.

Next up, the parent component

Let’s make the parent component — which we’re all aware by now, we’re calling <MasterForm/> — and initialize its state and methods.

We’re using a currentStep state that will be initialized with a default value of 1, indicating the first step (<Step1/>) of the form. We’ll update the state as the form progresses to indicate the current step.

class MasterForm extends Component { constructor(props) { super(props) // Set the initial input values this.state = { currentStep: 1, // Default is Step 1 email: '', username: '', password: '', } // Bind the submission to handleChange() this.handleChange = this.handleChange.bind(this) } // Use the submitted data to set the state handleChange(event) { const {name, value} = event.target this.setState({ [name]: value }) } // Trigger an alert on form submission handleSubmit = (event) => { event.preventDefault() const { email, username, password } = this.state alert(`Your registration detail: \n Email: ${email} \n Username: ${username} \n Password: ${password}`) } // Render UI will go here... }

OK, that’s the baseline functionality we’re looking for. Next, we want to create the shell UI for the actual form add call the child components in it, including the required state props that will be passed from <MasterForm/> via handleChange().

render() { return ( <React.Fragment> <h1>A Wizard Form!</h1> <p>Step {this.state.currentStep} </p> <form onSubmit={this.handleSubmit}> // Render the form steps and pass in the required props <Step1 currentStep={this.state.currentStep} handleChange={this.handleChange} email={this.state.email} /> <Step2 currentStep={this.state.currentStep} handleChange={this.handleChange} username={this.state.username} /> <Step3 currentStep={this.state.currentStep} handleChange={this.handleChange} password={this.state.password} /> </form> </React.Fragment> ) } One step at a time

So far, we’ve allowed users to fill the form fields, but we've provided no actual way to proceed to the next step or head back to the previous one. That calls for next and previous functions that check if the current step has a previous or next step; and if it does, push the currentStep prop up or down accordingly.

class MasterForm extends Component { constructor(props) { super(props) // Bind new functions for next and previous this._next = this._next.bind(this) this._prev = this._prev.bind(this) } // Test current step with ternary // _next and _previous functions will be called on button click _next() { let currentStep = this.state.currentStep // If the current step is 1 or 2, then add one on "next" button click currentStep = currentStep >= 2? 3: currentStep + 1 this.setState({ currentStep: currentStep }) } _prev() { let currentStep = this.state.currentStep // If the current step is 2 or 3, then subtract one on "previous" button click currentStep = currentStep <= 1? 1: currentStep - 1 this.setState({ currentStep: currentStep }) } }

We’ll use a get function that will check whether the current step is 1 or 3. This is because we have three-step form. Of course, we can change these checks as more steps are added to the form. We also want to display the next and previous buttons only if there actually are next and previous steps to navigate to, respectively.

// The "next" and "previous" button functions get previousButton(){ let currentStep = this.state.currentStep; // If the current step is not 1, then render the "previous" button if(currentStep !==1){ return ( <button className="btn btn-secondary" type="button" onClick={this._prev}> Previous </button> ) } // ...else return nothing return null; } get nextButton(){ let currentStep = this.state.currentStep; // If the current step is not 3, then render the "next" button if(currentStep <3){ return ( <button className="btn btn-primary float-right" type="button" onClick={this._next}> Next </button> ) } // ...else render nothing return null; }

All that’s left is to render those buttons:

// Render "next" and "previous" buttons render(){ return( <form onSubmit={this.handleSubmit}> {/* ... other codes */} {this.previousButton} {this.nextButton} </form> ) } Congrats, you’re a form wizard! &#x1f9d9;

That was the last step in this multi-step tutorial on multi-step forms. Whoa, how meta! While we didn’t go deep into styling, hopefully this gives you a solid overview of how to go about making complex forms less… complex!

Here’s that final demo again so you can see all the code in it’s full and glorious context:

See the Pen
React Simple Wizard Form
by Nathan Sebhastian (@nathansebhastian)
on CodePen.

React was made for this sort of thing considering it makes use of states, property changes, reusable components and such. I know that React may seem like a high barrier to entry for some folks, but I’ve written a book that makes it a much lower hurdle. I hope you check it out!

The post The Magic of React-Based Multi-Step Forms appeared first on CSS-Tricks.

The #StateOfCSS 2019 Survey

Css Tricks - Fri, 02/15/2019 - 5:19am

You know about the State of JavaScript survey, where thousands upon thousands of developers were surveyed about all-things-JS, from frameworks to testing and many other things in between? Well, Sacha Greif has launched one focused entirely on CSS.

This is super timely given a lot of the content we and other sites have been posting lately centered around learning, complexity, changing roles, and more. Sacha captures it nicely:

This is especially interesting since it comes at a time where many are talking about a “Great Divide” between the “front” of the front-end (HTML, CSS) and the “back” of the front-end (JavaScript and its many frameworks and libraries). [...] [T]he survey will be a great chance to take a snapshot of the community as it currently exists, and see how this evolves over the next couple years.

Sounds like a good goal. Let's help by putting some responses in there!

Take Survey

Direct Link to ArticlePermalink

The post The #StateOfCSS 2019 Survey appeared first on CSS-Tricks.

Getting to Grips with the Airtable API

Css Tricks - Thu, 02/14/2019 - 5:31am

The Airtable web app is pretty neat. You can use it like a spreadsheet but it’s useful for all sorts of other things too. The neatest thing about it for me is that it has an API so that you can treat it like a database.

I’ve been thinking about making weekly notes for the different teams I work with at Gusto to read about what the design systems team is working on, things we've fixed, and any bugs we've encountered during that might impact other designers and engineers across our organization. I’ve spent a couple of hours thinking about how we might use Airtable to collect a whole bunch of data and then use its API to extract that info and show it in a web app.

Here’s an example of what we’ll end up building, which is basically a React web app that’s using Airtable as a nifty sorta CMS:

To get started, we have to head on over to the command line and run the following (but first make sure npm is installed):

npx create-react-app airtable-test

This will create a new directory called airtable-test which is where we’ll be making our little React app. If we run yarn start in the command line after that’s finished installing, then we’ll see the default page for the project:

And, if we open up src/App.js in that airtable-test directory, we can see how this page is being rendered with React:

import React, { Component } from 'react'; import logo from './logo.svg'; import './App.css'; class App extends Component { render() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit src/App.js and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </header> </div> ); } } export default App;

Now that we have React up and running, we can go ahead and install airtable in the command line which will let us interact with the Airtable API:

npm i airtable

Once we’ve done that, we’ll need to create an Airtable account and create a project. We should wind up with something like this spreadsheet:

Now we can then head to airtable.com/api and select our project so that is serves as data we're pulling from. In this case, I selected “Design Systems Projects” which you can see right at the bottom here:

This will send us to a handy docs website that gives us an incredibly easy to read API for our specific project! Scrolling down we’ll find our API key which we’ll need to access this data as well as a ton of examples that we can use to manipulate the data we get back:

Let's head back to App.js in our airtable-test directory, delete all the code in that file, and replace it with the following:

import React, { Component } from 'react'; import Airtable from 'airtable'; const base = new Airtable({ apiKey: 'XXXXXXXXXXX' }).base('XXXXXXXXXXX');

Make sure to replace those Xs with the details that you can see in that Airtable API doc we just opened. But now that we’ve done all the setup, we can finally get around to creating our interface by calling data from our spreadsheet.

In App.js we can start to construct the App component:

class App extends Component { constructor(props) { super(props); this.state = { records: [] }; } render() { return { <div className="App">Hello</div> } } } }

All this will do for now is setup the app’s state and then render “Hello” on the page. Next up, we’ll be add each record from Airtable to that state.

First thing that’s important to note below: in componentDidMount() we’ll be selecting Updates which is just a way of telling Airtable that we want the spreadsheet called Updates. Make sure that this name is the same name as the spreadsheet. We’ll also be looping through all the records, or rows, of our table in that function too:

class App extends Component { constructor(props) { super(props); this.state = { records: [] }; } componentDidMount() { base('Updates').select({view: 'Grid view'}) .eachPage( (records, fetchNextPage) => { this.setState({ records }); console.log(records); fetchNextPage(); } ); } render() { return ( <div className="App"> <div>Hello</div> </div> ); } }

fetchNextPage() is the Airtable API’s way of giving us the next record in our spreadsheet and it’s neat that it will keep going until there are no more records. Again, we’re not doing anything with that data yet; we only want to make sure everything is working correctly at this point.

Open up the console in DevTools and we should see something like this:

Array(4) [ {…}, {…}, {…}, {…} ]

And if we dive through each of the objects in this array, then we should find all the data from the spreadsheet! Doing this bit always feels like magic to me.

Anyway, next up we can update our render() function like so:

render() { return ( <div className="App"> {this.state.records.length > 0 ? ( this.state.records.map((record, index) => <div key={index}> <h2>{record.fields['Date']}</h2> {record.fields['UI Kit']} {record.fields['Component Library']} </div> ) ) : ( <p>Loading...</p> )} </div> </div> ); }

We’re going to be looping through the state that we setup earlier and then rendering the record.fields[] for each column in our spreadsheet. We have a Date, UI Kit, and Component Library column, and once we’ve updated our App.js with the code above, we should see all the content from our spreadsheet!

It’s like magic! But why does this data look so weird? Well, it’s because I wanted to write Markdown in each cell, so now we’ll need to use a parser to convert that data into good ol’ fashioned HTML. First, we need to head back to the command line though:

npm i showdown

showdown will help us parse all that Markdown we’ve written in our Airtable spreadsheet. After installing it, we only need to import it at the top of our App.js file, like this:

import showdown from 'showdown'; const markdownConverter = new showdown.Converter();

After the componentDidMount() function, we can create another function that will create our HTML using showdown:

createHTML(markdown){ return( markdownConverter.makeHtml(markdown) ) }

It’s a little iffy, but it makes me feel like the code is a bit tidier this way. Now we can update our render() function:

render() { return ( <div className="App"> {this.state.records.length > 0 ? ( this.state.records.map((record, index) => <div key={index}> <h2>{new Date(record.fields['Date']).toISOString().split('T', 1)}</h2> <div dangerouslySetInnerHTML={{__html: this.createHTML(record.fields['UI Kit'])}} /> <div dangerouslySetInnerHTML={{__html: this.createHTML(record.fields['Component Library'])}} /> </div> ) ) : ( <p>Loading...</p> )} </div> ); }

We’re doing a couple of new things here: we’re using dangerouslySetInnerHTML in each div which, in turn, uses our createHTML function to convert the data from each column (specifically, the UI Kit and Component Library columns). We’re also converting the dates of each row into headings to make things a bit easier to read.

And with that we’re pretty much done! Here’s the final App.js:

import React, { Component } from 'react'; import Airtable from 'airtable'; import showdown from 'showdown'; const markdownConverter = new showdown.Converter(); const base = new Airtable({ apiKey: 'xxxxxxx' }).base('xxxxxxx'); class App extends Component { constructor(props) { super(props); this.state = { records: [] }; } componentDidMount() { base('Updates').select({view: 'Grid view'}) .eachPage( (records, fetchNextPage) => { this.setState({ records }); fetchNextPage(); } ); } createHTML(markdown){ return( markdownConverter.makeHtml(markdown) ) } render() { return ( <div className="App"> {this.state.records.length > 0 ? ( this.state.records.map((record, index) => <div key={index}> <h2>{new Date(record.fields['Date']).toISOString().split('T', 1)}</h2> <div dangerouslySetInnerHTML={{__html: this.createHTML(record.fields['UI Kit'])}} /> <div dangerouslySetInnerHTML={{__html: this.createHTML(record.fields['Component Library'])}} /> </div> ) ) : ( <p>Loading...</p> )} </div> ); } } export default App;

There’s still a ton of updates we could make to improve things. I took a first pass at styling, but we probably want to do things like improve the date format and maybe have some kind of indication as to which updates refer to which rows in the spreadsheet. Maybe we could even toggle showing which information to show depending on whether you’re a designer or engineer.

Anyway! I think this is a good start to getting to grips with the Airtable API and I’d love to hear about how you use it in the comments below.

The post Getting to Grips with the Airtable API appeared first on CSS-Tricks.

Use monday.com to manage and share projects all in one place

Css Tricks - Thu, 02/14/2019 - 5:29am

(This is a sponsored post.)

We've talked quite a bit about project management and workflows around here at CSS-Tricks, not because it's the core of what we do as designers and developers, but because we all play a role in it as part of a team and because it impacts the quality of our work at the end of the day.

That's why having a good system in place is such a benefit both to us and to teams as a whole. Where can you find a system like that? You might want to start by looking at monday.com. Yes, it's a project management tool but it actually goes way beyond that. Where some other platforms out there stop at task lists, calendars, and milestones, monday.com does those plus team collaboration.

If you've ever felt out of the loop on a project, had a surprise change in scope, or even been curious what other folks on your team have been up to, that's where monday.com really shines. It's people-centric, giving you and others insight into activity across an entire project through news feeds, messaging, shared assets, clearly defined user roles, among any other things. It's what a healthy, transparent, and collaborative team environment looks like.

We've only scratched the surface here, but lucky for you, there's a free 14-day trial to check out everything that monday.com has to offer. Go for it!

Try it Now

Direct Link to ArticlePermalink

The post Use monday.com to manage and share projects all in one place appeared first on CSS-Tricks.

The Smart Ways to Correct Mistakes in Git

Css Tricks - Wed, 02/13/2019 - 1:09pm

The world of software development offers an infinite amount of ways to mess up: deleting the wrong things, coding into dead ends, littering commit messages with typos, are a mere few of the plentitude.
??
??Fortunately, however, we have a wonderful safety net under our feet in the form of Git when we’re working with version control. Not that you and I need a safety net, of course, because we never make mistakes, right? Sure, sure. But for the benefit of everyone else, let's take a tour of some of the "undo" tools in Git that can save us from ourselves.
??
??
??
??

Fixing the last commit

??
??Messing up a commit is all too easy. Classic case in point: making a typo in a commit message. Another? Forgetting to add a change to the staging area. And in many cases, we instantly realize our mistake — right after hitting the Enter key, naturally.
??
??Luckily, Git makes it ridiculously easy to fix the very last commit. Let's say we had just hit Enter on the following command:

??

git commit -m "Massage full of typohs"

??
??And (as if this orthographic mess wasn't bad enough) let's say we also forgot to add another changed file to the staging area. We can correct both of our mistakes with the following two commands:
??

git add forgotten-changes.js ??git commit --amend -m "A sensible message"

??
??The magic ingredient is the --amend? flag: when using it on a commit, Git will correct the very last commit — with any staged changes and the new message.
??
??A short word of warning, though: only use --amend? on commits that haven't been pushed to a remote repository, yet. The reason is that Git replaces the original, bad commit with the amended version. Afterwards, it looks as if the original commit never happened. Yeah, that’s good for concealing mistakes, but only if we haven't already published this mistake on the remote server.
????
??

Undoing local changes

??
??Everyone’s had days like this: spend all morning hacking away, only to admit to yourself that the last few hours were a waste of time. Gotta start over and undo much (or all) of that work.
??
??But this is one of the reasons for using Git in the first place — to be able to try out things without the fear that we might break something.
??
??Let's take stock in an example situation:
??

git status ?? modified: about.html ?? deleted: imprint.html ?? modified: index.html

??
??Now, let's assume that this is one of the wasted hacking days described above. We ought to have kept our hands off of about.html and not deleted imprint.html. What we now want is to discard our current changes in these files — while keeping the brilliant work done in index.html. ??The git checkout? command can help in this case. Instead, we’ve gotta get more specific with which files to check out, like this:

??

git checkout HEAD about.html imprint.html

??This command restores both about.html and imprint.html to their last committed states. Phew, we got away from a black eye!
??
??We could take this one step further and discard specific individual lines in a changed file instead of tossing out the entire thing! I’ll admit, it’s rather complicated to make it happen on the command line, but using a desktop Git client like Tower is a great way to go about it:

??
??For those really bad days, we might want to bring out the big guns in the form of:
??
??

git reset --hard HEAD

??
??While we only restored specific files with checkout?, this command resets our whole working copy. In other words, reset? restores the complete project at its last committed state. ??Similar to --amend?, there's something to keep in mind when using checkout? and reset?: discarding local changes with these commands cannot be undone! They have never been committed to the repository, so it's only logical that they cannot be restored. Better be sure that you really want to get rid of them because there’s no turning back!
??
??

Undoing and reverting an older commit

??
??In many cases, we only realize a mistake much later, after it has long been committed to the repository.

??How can we get rid of that one bad commit? Well, the answer is that we shouldn't… at least in most cases. Even when "undoing" things, Git normally doesn't actually delete data. It corrects it by adding new data. Let's see how this works using our "bad guy" example:
??
??

git revert 2b504bee

??
??By using git revert? on that bad commit, we haven't deleted anything. Quite the contrary:

??Git automatically created a new commit with changes that reverts the effects of the "bad" commit. So, really, if we started with three commits and were trying to correct the middle one, now we have four total commits, with a new one added that corrects the one we targeted with revert?.
????
??

Restoring a previous version of a project

??
??A different use case is when we want to restore a previous version of our project. Instead of simply undoing or reverting a specific revision somewhere in our commit history, we might really want to turn back time and return to a specific revision.
??
??In the following example scenario, we would declare all the commits that came after "C2" as unwanted. What we want is to return to the state of commit "C2" and forget everything that came after it in the process:

??The command that's necessary is already (at least partly) familiar to you based on what we’ve already covered:
??
??

git reset --hard 2b504bee

??
??This tells git reset? the SHA-1 hash of the commit we want to return to. Commits C3 and C4 then disappear from the project's history.
??
??If you're working in a Git client, like Tower, both git revert? and git reset are available from the contextual menu of a commit item:

??

??Deleting commits, restoring deleted branches, dealing with conflicts, etc. etc. etc.

??
??Of course, there are many other ways to mess up things in a software project. But luckily, Git also offers many more tools for undoing the mess.
??
??Have a look at the "First Aid Kit for Git" project that I and other folks on the Tower team have created if you want to learn more about the scenarios we covered in this post, or about other topics, like how to move commits between branches, delete old commits, restore deleted branches or gracefully deal with merge conflicts. It’s a totally free guide that includes 17 videos and a handy cheat sheet you can download and keep next to your machine.

??In the meantime, happy undoing!

The post The Smart Ways to Correct Mistakes in Git appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.