Developer News

Better Form Inputs for Better Mobile User Experiences

Css Tricks - Fri, 04/17/2020 - 5:08am

Here’s one simple, practical way to make apps perform better on mobile devices: always configure HTML input fields with the correct type, inputmode, and autocomplete attributes. While these three attributes are often discussed in isolation, they make the most sense in the context of mobile user experience when you think of them as a team. 

There’s no question that forms on mobile devices can be time-consuming and tedious to fill in, but by properly configuring inputs, we can ensure that the data entry process is as seamless as possible for our users. Let’s take a look at some examples and best practices we can use to create better user experiences on mobile devices.

Use this demo to experiment on your own, if you’d like. Using the correct input type

This is the easiest thing to get right. Input types, like email, tel, and url, are well-supported across browsers. While the benefit of using a type, like tel over the more generic text, might be hard to see on desktop browsers, it’s immediately apparent on mobile.

Choosing the appropriate type changes the keyboard that pops up on Android and iOS devices when a user focuses the field. For very little effort, just by using the right type, we will show custom keyboards for email, telephone numbers, URLs, and even search inputs

Text input type on iOS (left) and Android (right) Email input type on iOS (left) and Android (right) URL input type on iOS (left) and Android (right) Search input type on iOS (left) and Android (right)

One thing to note is that both input type="email" and input type="url" come with validation functionality, and modern browsers will show an error tooltip if their values do not match the expected formats when the user submits the form. If you’d rather turn this functionality off, you can simply add the novalidate attribute to the containing form.

A quick detour into date types

HTML inputs comprise far more than specialized text inputs — you also have radio buttons, checkboxes, and so on. For the purposes of this discussion, though, I’m mostly talking about the more text-based inputs

There is a type of input that sits in the liminal space between the more free-form text inputs and input widgets like radio buttons: date. The date input type comes in a variety of flavors that are well-supported on mobile, including date, time, datetime-local, and month. These pop up custom widgets in iOS and Android when they are focused. Instead of triggering a specialized keyboard, they show a select-like interface in iOS, and various different types of widgets on Android (where the date and time selectors are particularly slick). 

I was excited to start using native defaults on mobile, until I looked around and realized that most major apps and mobile websites use custom date pickers rather than native date input types. There could be a couple reasons for this. First, I find the native iOS date selector to be less intuitive than a calendar-type widget. Second, even the beautifully-designed Android implementation is fairly limited compared to custom components — there’s no easy way to input a date range rather than a single date, for instance. 

Still, the date input types are worth checking out if the custom datepicker you’re using doesn’t perform well on mobile. If you’d like to try out the native input widgets on iOS and Android while making sure that desktop users see a custom widget instead of the default dropdown, this snippet of CSS will hide the calendar dropdown for desktop browsers that implement it:

::-webkit-calendar-picker-indicator {   display: none; } Date input type on iOS (left) and Android (right) Time input type on iOS (left) and Android (right)

One final thing to note is that date types cannot be overridden by the inputmode attribute, which we’ll discuss next.

Why should I care about inputmode?

The inputmode attribute allows you to override the mobile keyboard specified by the input’s type and directly declare the type of keyboard shown to the user. When I first learned about this attribute, I wasn’t impressed — why not just use the correct type in the first place? But while inputmode is often unnecessary, there are a few places where the attribute can be extremely helpful. The most notable use case that I’ve found for inputmode is building a better number input.

While some HTML5 input types, like url and email, are straightforward, input type="number" is a different matter. It has some accessibility concerns as well as a somewhat awkward UI. For example, desktop browsers, like Chrome, show tiny increment arrows that are easy to trigger accidentally by scrolling.

So here’s a pattern to memorize and use going forwards. For most numeric inputs, instead of using this: 

<input type="number" />

…you actually want to use this:

<input type="text" inputmode="decimal" />

Why not inputmode="numeric" instead of inputmode="decimal" ? 

The numeric and decimal attribute values produce identical keyboards on Android. On iOS, however, numeric displays a keyboard that shows both numbers and punctuation, while decimal shows a focused grid of numbers that almost looks exactly like the tel input type, only without extraneous telephone-number focused options. That’s why it’s my preference for most types of number inputs.

iOS numeric input (left) and decimal input (right) Android numeric input (left) and decimal input (right)

Christian Oliff has written an excellent article dedicated solely to the inputmode attribute.

Don’t forget autocomplete

Even more important than showing the correct mobile keyboard is showing helpful autocomplete suggestions. That can go a long way towards creating a faster and less frustrating user experience on mobile.

While browsers have heuristics for showing autocomplete fields, you cannot rely on them, and should still be sure to add the correct autocomplete attribute. For instance, in iOS Safari, I found that an input type="tel" would only show autocomplete options if I explicitly added a autocomplete="tel" attribute.

You may think that you are familiar with the basic autocomplete options, such as those that help the user fill in credit card numbers or address form fields, but I’d urge you to review them to make sure that you are aware of all of the options. The spec lists over 50 values! Did you know that autocomplete="one-time-code" can make a phone verification user flow super smooth?

Speaking of autocomplete…

I’d like to mention one final element that allows you to create your own custom autocomplete functionality: datalist. While it creates a serviceable — if somewhat basic — autocomplete experience on desktop Chrome and Safari, it shines on iOS by surfacing suggestions in a convenient row right above the keyboard, where the system autocomplete functionality usually lives. Further, it allows the user to toggle between text and select-style inputs.

On Android, on the other hand, datalist creates a more typical autocomplete dropdown, with the area above the keyboard reserved for the system’s own typeahead functionality. One possible advantage to this style is that the dropdown list is easily scrollable, creating immediate access to all possible options as soon as the field is focused. (In iOS, in order to view more than the top three matches, the user would have to trigger the select picker by pressing the down arrow icon.)

You can use this demo to play around with datalist:

CodePen Embed Fallback

And you can explore all the autocomplete options, as well as input type and inputmode values, using this tool I made to help you quickly preview various input configurations on mobile.

In summary

When I’m building a form, I’m often tempted to focus on perfecting the desktop experience while treating the mobile web as an afterthought. But while it does take a little extra work to ensure forms work well on mobile, it doesn’t have to be too difficult. Hopefully, this article has shown that with a few easy steps, you can make forms much more convenient for your users on mobile devices.

The post Better Form Inputs for Better Mobile User Experiences appeared first on CSS-Tricks.

Thank You, Christopher Schmitt

Css Tricks - Thu, 04/16/2020 - 10:15am

It’s incredibly sad that Christopher Schmitt passed away last week¹. I keep thinking about how Christopher was one of the best dudes I knew. Just incredibly kind and thoughtful all the way through. I know everyone says that about people after they pass, but I really mean it here. I’m sure we all know people that we like quite a bit, but hey, we know they can be an asshole sometimes too. Not Christopher, at least not to me. He was always good to me in ways I’ll never be able to reciprocate.

Here’s the most important thing:

We (a group of developer friends) would like to build a site of memories that people have of Christopher. We have our own, but we’d like to collect as many memories from as many people as possible to make this a true memorial to him. If you have one you would like to share publicly, please submit it to this little site just for that.

I hardly know where to start reminiscing about Christopher. Broadly: I spoke at more conferences thrown by Christopher (and Ari) than anyone else. At least a dozen. He used to throw one called In Control in Orlando that I spoke at a number of times and met some early web friends that I’m still close with today! Stephanie Rewis mentioned to me that’s where we met the first time and she remembers me coding away on a yet-to-be released CodePen while there. In Control went to Hawaii one year, along with the first-ever CSS Dev Conf, bringing me to Hawaii for the first time in my life, where I remember driving around the island with Daniel Burka. CSS Dev Conf went all sorts of amazing places, and I went to all of them! Estes Park, New Orleans, The Queen Mary… all these incredible locations that were all incredible memories for me.

And all I have are blurry, distant photos of him like this:

Christopher and Ari also ran an absolute ton of online conferences. CSS Summit, RWD Summit, SVG Summit… they ran a ton of them and they were really ahead of their time. I remember a funny moment where I had just moved to a new city and my internet wasn’t installed yet, but I still had to present online at one of these, so I did it out of my neighbors garage (as their kids slept), and the light in the garage kept going out because it didn’t detect movement. &#x1f62c;

The people I met through Christopher are too many to count. He was a great connector in that way. His influence on the web was tremendous through his direct work, like writing (what, a dozen books?), blogging (even here!), speaking, and podcasting (e.g. The Non Breaking Space Show) but when you consider the people he brought together, his influence is immeasurable.

I literally made money off the guy. In the early years of ShopTalk, when it was tough to sell podcast spots at all, Christopher would sponsor every episode of ShopTalk, which probably gave us the boost that ensured it’s still happening today. Who knows what would have happened without that.

One of the things I liked best about Christopher is that he was a damn nerd. Through and through. In a way that made you envious that you could one day hope to up your nerd level that high. Guy had a Chewbacca costume that he wore regularly. His Instagram is full of snaps of him meeting other famous nerds.

I hope you still got those black Converses on wherever you are, buddy.

(And remember, if you have a memory with Christopher, please share it.)

  1. It wasn’t COVID-19. Poor guy was dealt bad cards from day one for his health and he fought it the the best he could.

The post Thank You, Christopher Schmitt appeared first on CSS-Tricks.

Creating Color Themes With Custom Properties, HSL, and a Little calc()

Css Tricks - Thu, 04/16/2020 - 10:01am

Before the advent of CSS custom properties (we might call them “variables” in this article as that’s the spirit of them), implementing multiple color schemes on the same website usually meant writing separate stylesheets. Definitely not the most maintainable thing in the world. Nowadays, though, we can define variables in a single stylesheet and let CSS do the magic.

Even if you aren’t offering something like user-generated or user-chosen color themes, you might still use the concept of theming on your website. For example, it is fairly common to use different colors themes across different areas of the site.

We’re going to build out an example like this:

Same layout, different colors.

In this example, all that changes between sections is the color hue; the variations in lightness are always the same. Here’s an example of a simplified color palette for a specific hue:

CodePen Embed Fallback

A palette of multiple hues might look something like this:

CodePen Embed Fallback

This would take effort to do with RGB color value, but in HSL only one value changes.

Enter custom properties

Custom properties have been around for a while and are widely supported. Polyfills and other solutions for IE 11 are also available.

The syntax is very similar to traditional CSS. Here is an overview of the basic usage:

CodePen Embed Fallback

It’s common to see variables defined on the :root pseudo-element, which is always <html> in HTML, but with higher specificity. That said, variables can be defined on any element which is useful for scoping specific variables to specific elements. For example, here are variables defined on data attributes:

CodePen Embed Fallback Adding calc() to the mix

Variables don’t have to be fixed values. We can leverage the power of the calc() function to automatically calculate values for us while adhering to a uniform pattern:

CodePen Embed Fallback

Since CSS doesn’t support loops, a preprocessor would be handy to generate a part of the code. But remember: CSS variables are not the same as Sass variables.

Implementing CSS variables

What we’re basically trying to do is change the color of the same component on different sections of the same page. Like this:

CodePen Embed Fallback

We have three sections in tabs with their own IDs: #food, #lifestyle, and #travel. Each section corresponds to a different hue. The  data-theme-attribute on the div.wrapper element defines which hue is currently in use.

When #travel is the active tab, we’re using the --first-hue variable, which has a value of 180°. That is what gets used as the --hue value on the section, resulting in a teal color:

<div class="wrapper" data-theme="travel"> .wrapper[data-theme="travel"] {   --hue: var(--first-hue);  /* = 180° = teal */ }

Clicking any of the tabs updates the data-theme attribute to the ID of the section, while removing the hash (#) from it. This takes a smidge of JavaScript. That’s one of the (many) nice things about CSS: they can be accessed and manipulated with JavaScript. This is a far cry from preprocessor variables, which compile into values at the build stage and are no longer accessible in the DOM.

<li><a href="#food">Food</a></li> const wrapper = document.querySelector('.wrapper'); document.querySelector("nav").addEventListener('click', e => {   e.preventDefault();   e.stopPropagation();   // Get theme name from URL and ditch the hash   wrapper.dataset.theme ='href').substr(1); }) Progressive enhancement

When we use JavaScript, we should be mindful of scenarios where a user may have disabled it. Otherwise, our scripts — and our UI by extension — are inaccessible. This snippet ensures that the site content is still accessible, even in those situations:

document.querySelectorAll('section').forEach((section, i) => {   if (i) { // hide all but the first section = 'none';   } })

This merely allows the tabs to scroll up the page to the corresponding section. Sure, theming is gone, but providing content is much more important.

While I chose to go with a single-page approach, it’s also possible to serve the sections as separate pages and set [data-theme] on the server side. 

Another approach

So far, we’ve assumed that color values change linearly and are thus subject to a mathematical approach. But even in situations where this is only partially true, we may still be able to benefit from the same concept. For instance, if lightness follows a pattern but hue doesn’t, we could split up the stylesheet like this:

<head>   <style>     :root {       --hue: 260;     }   </style>   <link rel="stylesheet" href="stylesheet-with-calculations-based-on-any-hue.css"> </head> Supporting web components

Web components are an exciting (and evolving) concept. It’s enticing to think we can have encapsulated components that can be reused anywhere and theme them on a case-by-case basis. One component with many contexts!

We can use CSS variable theming with web components. It requires us to use a host-context() pseudo-selector. (Thanks to habemuscode for pointing this out to me!)

:host-context(body[data-theme="color-1"]) {   --shade-1: var(--outsideHSL); } In summary…

Theming a website with CSS custom properties is much easier than the workaround approaches we’ve resorted to in the past. It’s more maintainable (one stylesheet), performant (less code), and opens up new possibilities (using JavaScript). Not to mention, CSS custom properties become even more powerful when they’re used with HSL colors and the calc() function.

We just looked at one example where we can change the color theme of a component based on the section where it is used. But again, there is much more opportunity here when we start to get into things like letting users change themes themselves – a topic that Chris explores in this article.

The post Creating Color Themes With Custom Properties, HSL, and a Little calc() appeared first on CSS-Tricks.

Jetpack Instant Search!

Css Tricks - Thu, 04/16/2020 - 9:19am

Jetpack has had a search feature for a while. Flip it on, and it replaces your built-in WordPress search (which is functional, but not particularly good) with an Elasticsearch-powered solution that is faster and has better results. I’ve been using that for quite a while here on CSS-Tricks, which was an upgrade from using a Google Custom Search Engine.

Jetpack just upped their game again with a brand new search upgrade. You can use Jetpack search how you were already, or you can flip on Instant Search and take advantage of this all-new search experience (inside and out).

Flipping on Jetpack Instant Search from Jetpack Settings A Full Page Experience

Instant Search provides a full page-covering search experience. I think it’s awesome. When a user is searching, that’s the mindset they are in and giving them all the space they need to accomplish that goal is great. Here’s me searching (video):

Note that I misspell the word “margin” and the results are fine. You get a full page experience on mobile as well.

Best I can tell, CSS-Tricks gets a couple hundred thousand on-site searches per month, so having a great experience there is very important to me. I don’t even wanna mess around with bad on-site search experiences, or products that are too expensive. I’d rather send people to a site-scoped Google search than a bad on-site search. Fortunately, Instant Search is about as good of an on-site search experience as I can imagine, especially for the zero-work it takes to implement.

Design Control

You have some control over the look of things from the Customizer.

Instant Search is designed to work on any site, so you probably don’t need to do much. I was really surprised how well it worked out-of-the-box for CSS-Tricks. As a CSS control freak, I did ship a handful of design tweaks to it, but that’s just because I love doing that kind of thing.

Tweaks No Longer Needed

With the previous version of Jetpack Search, I had custom code in place to tweak Elasticsearch. I did things like factoring in comment counts as an indicator of popularity, so that I could be sure our best content was high in the results. Remember as powerful as this search is, it doesn’t have a model of the entire internet to calculate relevancy from like Google does. Good news though:

To further improve our search algorithm, we started experimenting with adding the percentage of pageviews from the past 30 days into the index. We ended up finding that pageviews are a much better ranking signal because it somewhat combines both popularity and recency. So now most of our result ranking is strongly influenced by the number of pageviews a post or page gets. Conveniently, if you get a lot of Google Search traffic, our search results should be heavily influenced by Google’s ranking algorithm.

Emphasis mine. With Jetpack Instant Search, I was able to rip all that custom code out (removing code always feels great) because the new algorithms are doing a great job with ranking results.


Now Jetpack Search is ala-carte rather than baked into specific plans. Don’t need it? You don’t pay for it. Only need this feature? You can buy it regardless of what plan you are on.

I’m told the pricing is about scope. Jetpack plans are about features, not scale of site, but that doesn’t make much sense for search where the scale of the site matters a ton. So it’s a sliding scale based on the “records” you have, which are basically posts and pages.

Sliding scale of pricing

I would think a lot of sites fall into the $25/month (15% off for annual) category. You probably mostly start caring about on-site search above 1,000 records and 10,000 records is a ton. I pay for the tier one up from that (~$612 a year) only because our (now archived) bbPress forums pushes the number over 10,000. That’s a perfectly fair price for this for a site like mine.

Wish List

My #1 thing is that I wish it was easy to remove certain things from search results. We have tons and tons of records from our bbPress forums that I made the (hard) call to close this year. Removing those records would pull me down into a smaller pricing tier, but more importantly, I’d rather just not show those results in search at all.

It’s not just CSS-Tricks being in an unusual situation. I’ve also turned on Jetpack Instant Search on the CodePen Documentation.

In that circumstance, I’d consider turning removing blog posts (believe it or not) from the search results, so instead just the Pages would show up which are our core documentation there. Or perhaps even better, blog posts are just turned off as a filter by default, but users could flip them on to see them in the results.

All in all, this is a huge upgrade to Jetpack and yet another reason I consider it the most important plugin I run on my WordPress sites. If you’re curious about other Jetpack features we use, we made a special page for that.

The post Jetpack Instant Search! appeared first on CSS-Tricks.

CSS Scrollbar With Progress Meter

Css Tricks - Wed, 04/15/2020 - 11:49am

Scrollbars are natural progress meters. How far the scrollbar is down or across is how much progress has been made scrolling through that element (often the entire page). But, they are more like progress indicators than meters, if you think of a meter as something that “fills up” as you go.

We can use some CSS trickery to make the scrollbar fill up as we go.

This will only work with -webkit- vendor-prefixed scrollbar-styling properties. In other words, these are non-standard. The standardized scrollbar styling properties are scrollbar-width and scrollbar-color, which can’t pull this kind of thing off, but are probably a safer bet in the long run. Still, the vendor-prefixed versions probably aren’t going anywhere, so if you consider this a weird form of progressive enhancement, that’s probably fine.

What’s the trick?

Essentially, it’s hanging a huge box-shadow off the top of the scrollbar thumb — or off the side if it’s a horizontally scrolling element.

:root { --shadow: #43a047; --scrollbarBG: #eee; --thumbBG: #66bb6a; } ::-webkit-scrollbar { width: 16px; } ::-webkit-scrollbar-track { background: var(--scrollbarBG); } ::-webkit-scrollbar-thumb { background-color: var(--thumbBG); box-shadow: 0 -100vh 0 100vh var(--shadow), 0 0 15px 5px black; } Demo CodePen Embed Fallback

I first saw this in a Pen by Myk.

That example didn’t differentiate the thumb part of the scrollbar at all, which makes it more meter-like, but also harder to use. My demo has a slightly different color thumb.

Can I really use this?

No! Aside from it being super weird and non-standard. Safari flips it’s lid and I have no idea how to fix it.

I do happen to have a favorite CSS trick that is highly related to this though.

I want to learn more about styling scrollbars

Cool, here you go.

The post CSS Scrollbar With Progress Meter appeared first on CSS-Tricks.

Using CSS to Set Text Inside a Circle

Css Tricks - Tue, 04/14/2020 - 4:57am

You want to set some text inside the shape of a circle with HTML and CSS? That’s crazy talk, right?

Not really! Thanks to shape-outside and some pure CSS trickery it is possible to do exactly that. 

However, this can be a fiddly layout option. We have to take lots of different things into consideration, like character count, word count, typeface variations, font sizing, font formatting, and responsive requirements to name a few. One size, does not fit all here. But hey, let’s do it anyway.

Here’s the goal: we want to display a <blockquote> and an author citation inside a circle shape. We also want to make the layout as flexible as we can. This layout won’t require any additional files and keeps the HTML markup squeaky clean.

This is what we’re striving for:

CodePen Embed Fallback

The shape-outside feature is not supported in Internet Explorer or Microsoft Edge 18 and below at the time of this writing.

First up, the HTML

We’re going to end up needing a wrapper element to pull this off, so let’s use the semantic <blockquote> as the inner element. The outside wrapper can be a div:

<div class="quote-wrapper">   <blockquote class="text" cite="">     <p>Experience design is the design of anything, independent of medium, or across media, with human experience as an explicit outcome, and human engagement as an explicit goal.</p>     <footer>– Jesse James Garrett</footer>   </blockquote> </div>

If you’re interested in a deep-dive on the HTML of quotes, you’re in luck. We’re going to set the quote itself in a <p> and the name of the author inside a <footer>. We’ve got class names for the CSS styling hooks we’ll need.

Next, some baseline CSS

Let’s start with the div wrapper. First, we’ll set the minimum (responsive) square size at 300px so it fits on smaller screens. then, we’ll add relative positioning (because we will need it later). 

.quote-wrapper {   height: 300px;   position: relative;   width: 300px; }

Now we’ll make the blockquote fill the whole wrapper and fake a circle shape with a radial gradient background. (That’s right, we are not using border-radius in this example).

.text {   background: radial-gradient(     ellipse at center,     rgba(0, 128, 172, 1) 0%,     rgba(0, 128, 172, 1) 70%,     rgba(0, 128, 172, 0) 70.3%   );   height: 100%;   width: 100%; }

One thing to note is that 70% displays a much rougher edge. I manually added very small percentage increments and found that 70.3% looks the smoothest.

Notice the edge on the right is much smoother than the edge on the left.

Now we have our base circle in place. Add these additional style rules to .text.

.text {   color: white;   position: relative;   margin: 0; }

Here’s what we have so far:

Giving text the CSS treatment

Let’s style the paragraph first:

.text p {   font-size: 21px;   font-style: italic;   height: 100%;   line-height: 1.25;   padding: 0;   text-align: center;   text-shadow: 0.5px 0.5px 1px rgba(0, 0, 0, 0.3); }

Let’s use the blockquote’s ::before pseudo-element to create our shaping. This is where the shape-outside property comes into play. We plot out the polygon() coordinates and float it to the left so the text wraps inside the shape.

.text::before {   content: "";   float: left;   height: 100%;   width: 50%;   shape-outside: polygon(     0 0,   98% 0,     50% 6%,     23.4% 17.3%,     6% 32.6%,     0 50%,     6% 65.6%,     23.4% 82.7%,     50% 94%,     98% 100%,     0 100%   );   shape-margin: 7%; }

Let’s change the radial background color to red. The path editor polygon points and connecting lines are also blue. We are changing this color temporarily for greater contrast with the editor tool.

background: radial-gradient(   ellipse at center,   rgba(210, 20, 20, 1) 0%,   rgba(210, 20, 20, 1) 70%,   rgba(210, 20, 20, 0) 70.3% );

I like Firefox’s developer tools because it has super handy features like a shape-outside path editor.  Click on the polygon shape in the inspector to see the active shape in the browser window. Big thumbs up to the Mozilla dev team for creating a very cool interface!

The Firefox shape editor tool also works for clip-path and <basic-shape> values.

Here’s what we have at this point:

Those points along the shape are from Firefox’s editing tool.

We can do the same sort of thing for the paragraph’s ::before pseudo-element. We use the shape-outside to make the same polygon, in reverse, then float it to the right.

.text p::before {   content: "";   float: right;   height: 100%;   width: 50%;   shape-outside: polygon(     2% 0%,     100% 0%,     100% 100%,     2% 100%,     50% 94%,     76.6% 82.7%,     94% 65.6%,     100% 50%,     94% 32.6%,     76.6% 17.3%,     50% 6%     );   shape-margin: 7%; }

Looking good, but where did the footer go? It overflowed the <blockquote> (where the circular colored background is), so we’re unable to see that white text on a white background.

Styling the footer

Now we can style the <footer> and give it an absolute position to bring it back on top of the circle.

.quote-wrapper blockquote footer {   bottom: 25px;   font-size: 17px;   font-style: italic;   position: absolute;   text-align: center;   text-shadow: 0.5px 0.5px 1px rgba(0, 0, 0, 0.3);   width: 100%; }

Again, feel free to change the background color to suit your needs.

This is where the fiddly part comes in. The text itself needs to be styled in such a way that the number of words and characters work inside the shape. I used these CSS rules to help make it fit nicely:

  • font-size
  • shape-margin (we have two exclusion areas to adjust)
  • line-height
  • letter-spacing
  • font-weight
  • font-style
  • min-width  and min-height (to size of the .quote-wrapper container)
Adding the quote mark for some flourish

Did you see the giant quotation mark in the original demo? That’s what we want to make next.

We’ll take advantage of the ::before  pseudo-element for .quote-wrapper. Yet again, this will take a fair amount of fiddling to make it look right. I found line-height has a huge effect on the mark’s vertical position.

.quote-wrapper::before {   content: "\201C";   color: #ccc;   font-family: sans-serif, serif;   font-size: 270px;   height: 82px;   line-height: 1;   opacity: .9;   position: absolute;   top: -48px;   left: 0;   z-index: 1; } .dumb-quotes::before { content: "\0022"; } .dumb-quotes::after { content: "\0022"; }

There’s actually a difference between curly (“smart”) quote marks and straight (dumb) ones. I’d suggest using curly quote marks for dialogue and straight quote marks for coding.

Handling responsive styles

We should probably make our quote bigger on larger screens. I’m setting a breakpoint at 850px, but you may want to use something different.

@media (min-width: 850px) {   .quote-wrapper {     height: 370px;     width: 370px;   }   .quote-wrapper::before {     font-size: 300px;   }   .text p {     font-size: 26px;   }   .quote-wrapper blockquote footer {     bottom: 32px;   } } There we have it! CodePen Embed Fallback

We set HTML text inside a circular shape using a combination of old and new CSS techniques to make an appealing <blockquote> that commands attention. And we achieved our display goal without any additional dependencies, while still keeping the HTML markup clean and semantic.

I hope this article encourages you to explore new layout possibilities with shape-outside. Stay tuned for shape-inside.

The post Using CSS to Set Text Inside a Circle appeared first on CSS-Tricks.

No-Class CSS Frameworks

Css Tricks - Mon, 04/13/2020 - 11:51am

I linked up Water.css not long ago as an interesting sort of CSS framework. No classes. No <h2 class="is-title">. You just use semantic HTML and get styles. Is that going to “scale” very far? Probably not, but it sure is handy for styling things quickly, where — of course — you’re writing semantic HTML but don’t need to care tremendously about the look, other than it should look as decent as it can with low effort.

This week I saw MVP.css making the rounds. Same idea. There are a bunch more!

Even Foundation, while being a big honkin’ framework, does some pretty decent stuff classless-ly™.

The post No-Class CSS Frameworks appeared first on CSS-Tricks.

Styling in the Shadow DOM With CSS Shadow Parts 

Css Tricks - Mon, 04/13/2020 - 4:41am

Safari 13.1 just shipped support for CSS Shadow Parts. That means the ::part() selector is now supported in Chrome, Edge, Opera, Safari, and Firefox. We’ll see why it’s useful, but first a recap on shadow DOM encapsulation…

The benefits of shadow DOM encapsulation

I work at giffgaff where we have a wide variety of CSS code that has been written by many different people in many different ways over the years. Let’s consider how this might be problematic. 

Naming collisions

Naming collisions between classes can easily crop up in CSS. One developer might create a class name like .price. Another developer (or even the same one) might use the same class name, without knowing it.

CSS won’t alert you to any error here. Now, any HTML elements with this class will receive the styling intended for two completely different things.

Shadow DOM fixes this problem. CSS-in-JS libraries, like Emotion and styled-components, also solve this issue in a different way by generating random class names, like .bwzfXH. That certainly does help avoid conflicts! However, CSS-in-JS doesn’t prevent anybody from breaking your component in other ways. For example…

Base styles and CSS resets

Styles can be applied using HTML element selectors like <button> and <div>. These styles could break a component. Shadow DOM is the only thing that offers (almost) full encapsulation — you can rest assured that your component will look the same, even in a messy  !important  strewn codebase because each component is encapsulated.

/* This will have no effect on buttons inside shadow DOM */ button { background-color: lime !important; }

I wouldn’t say it’s good practice to style elements this way, but it happens. Even it does, those styles will have no effect on the shadow DOM.

It’s worth noting that inheritable styles like color, font and line-height are still inherited in a shadow DOM. To prevent that, use all: initial  or, preferably, all: revert once it has better browser support.

Let’s look at a common example of CSS applied directly to HTML elements. Consider this code from Eric Meyer’s reset

html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed,  figure, figcaption, footer, header, hgroup,  menu, nav, output, ruby, section, summary, time, mark, audio, video {   margin: 0;   padding: 0;   border: 0;   font-size: 100%;   font: inherit;   vertical-align: baseline; }

What if the component we’re working with makes use of the user agent’s default values for margin and padding? This reset might cause it to appear broken since those defaults are effectively wiped out.

Shadow DOM is a way to avoid these problems. Shadow DOM allows us to feel fully confident that a component will render as expected, regardless of what codebase it ends up in. Equally, none of the code meant only for a component can inadvertently affect anything else — all without resorting to onerous class naming conventions. Shadow DOM offers a level of encapsulation that can’t be achieved any other way.

Encapsulation is great, but we also want our components to be themeable and customizable. That’s been made far easier with the ::part selector. 

Styling shadow DOM with ::part()

Until now, the only way for CSS to modify the styling of a custom element from outside of the shadow DOM was to use CSS custom properties. In a strict design system where you only want to allow limited changes, that might be ideal. If you want your component to be more versatile, it creates a problem. Every CSS property you want to offer up for styling needs to be defined using a custom property. Just the sound of that seems tedious.

The situation is compounded further if we want to style a component differently based on pseudo-classes, like :hover. Basically, we end up with loads of custom properties. Let’s look at an example from Ionic, an open source set of web components. Just look at all the custom properties defined on the Ionic button component.

Go ahead, I’ll wait.

I counted 23 custom properties. Needless to say, that’s less than ideal.

Here’s an example using ::part() to style the element instead. 

CodePen Embed Fallback

In this Pen, I’m simply changing the color, border and background-color properties, but I could use whatever I want without being constrained by what custom properties have been defined. Notice that I can also style different states of the part using pseudo-classes, like :hover and :focus.

The entire component in this button example is being exposed for styling, but if your web component consists of multiple HTML elements, you can expose only selected parts of the component to this sort of styling — hence the name ::part. This stops users of the component from styling any arbitrary element inside the shadow tree. It is up the the component author to expose the parts of the component they explicitly want to. Other parts of the component can be kept visually uniform or make use of custom properties for a more minimal customizability. 

So, how do we set this up for our own components? Let’s look at using ::part to make certain elements of a web component eligible for styling. All we do is add a part attribute on the element we want to be exposed.

<div part="box">...</div>   <button>Click me</button>

In this example the div is customizable with the full gamut of CSS — any CSS property can be changed. The button, however, is locked down — it cannot be visually changed by anybody except the component author.

CodePen Embed Fallback

And the same way an HTML element can have multiple classes, an element can have multiple part names: 

<div part="box thing">...</div>

So that’s what we get with ::part: by exposing “parts” of an element we can provide some flexibility in how a web component is used while exercising protection in other areas. Whether it’s your design system, a component library, or what have you, the fact that CSS Shadow Parts are becoming mainstream gives us yet another exciting tool to work with.

The post Styling in the Shadow DOM With CSS Shadow Parts  appeared first on CSS-Tricks.

When debugging, your attitude matters

Css Tricks - Sun, 04/12/2020 - 2:32am

Julia Evans:

I was debugging some CSS last week, and I think that post is missing something important: your attitude.

Now – I’m not a very good CSS developer yet. I’ve never written CSS professionally and I don’t understand a lot of basic CSS concepts (I think I finally understood for the first time recently how position: absolute works). And last week I was working on the most complicated CSS project I’d ever attempted.

While I was debugging my CSS, I noticed myself doing some bad things that I normally would not! I was:

• making random changes to my code in the hopes that it would work
• googling a lot of things and trying them without understanding what they did
• if something broke, reverting my changes and starting again

This strategy was exactly as effective as you might imagine (not very effective!), and it was because of my attitude about CSS! I had this unusual-for-me belief that CSS was Too Hard and impossible for me to understand. So let’s talk about that attitude a bit!

It’s super unfortunate this specific bug (a difference in z-index behavior between Chrome and Firefox) is what was giving Julia a hard time. Those kind of cross-browser differences are fewer and farther between these days, thankfully. I’m certainly sympathetic to CSS being super tricky sometimes, and it can be that way without dealing with an actual browser bug.

But I like the sentiment: if you go into a tricky problem with a positive I can do this attitude starting with the basics, you can do it.

I think literally everything in life is easier and better with a better attitude. Food tastes better! Reminds me of my favorite mis-remembered quote from good ol’ Uncle Iroh from The Last Airbender:

The best tasting tea is the tea you drink when you are in a good mood.

Direct Link to ArticlePermalink

The post When debugging, your attitude matters appeared first on CSS-Tricks.

Thinking in Behaviors, Not Screen Sizes

Css Tricks - Fri, 04/10/2020 - 12:01pm

Chase McCoy wrote a nifty post about the “gap problem” when making a grid of items. His argument might be summarized like this: how should we space elements with margins in CSS? He notes that the gap property isn’t quite ready for prime time when it comes to using it with flexbox, like this:

.grid { display: flex; gap: 10px; }

Right now, using gap with flexbox is only supported in Firefox and I’ve already caught myself forgetting about that in a few projects. So watch out for that.

Anyway, the part about Chase’s blog post that I love is where he mentions Andy Bell’s technique for creating a responsive layout with no media queries, like this:

.grid { display: grid; grid-gap: 10px; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }

This CSS is doing the following:

  • Make a grid with a 10px gap between each column and row.
  • Each column should have a minimum width (150px).
  • Each column should also be equal width (1fr).
  • The grid should auto-fill as many columns that can fit.

The nifty thing about all this is that our grid is now effectively responsive because of minmax — if you resize the browser, then the grid will snap down into fewer columns, just like this:

No media queries at all! Although sure, there’s a few other ways that you could get this to work but I think this is neat not just because we’re avoiding media queries — instead, it’s because it teaches us to think in a new way when designing and building components.

Chase continues:

With this technique, instead of using breakpoints to specify the screen size where your items should stack, you specify the minimum size an element should be before it stacks. I like this because it encourages developers to think about responsive design in terms of behaviors instead of screen sizes.

“Behaviors instead of screen sizes” is such a great way to think about component design! A lot of the problems I’ve encountered when making components for a design system is when I’ve been thinking about screen sizes — mobile, tablet, desktop, etc. — and trying to make those components fit within those constraints.

Thinking in behaviors is always more effective because there are so many things that can impact a component beyond what screen or device width we’re working with. Perhaps we want that component to fit inside another component. Or we want to align some helper text to the side of it for comparison.

Either way, thinking about behaviors instead of screen sizes isn’t really going to be fully possible until we have container queries, as Chris writes:

Container queries are always on the top of the list of requested improvements to CSS. The general sentiment is that if we had container queries, we wouldn’t write as many global media queries based on page size. That’s because we’re actually trying to control a more scoped container, and the only reason we use media queries for that now is because it’s the best tool we have in CSS. I absolutely believe that.

The post Thinking in Behaviors, Not Screen Sizes appeared first on CSS-Tricks.

Tips for Writing Animation Code Efficiently

Css Tricks - Fri, 04/10/2020 - 4:46am

I’ve been coding web animations and helping others do the same for years now. However, I have yet to see a concise list of tips focused on how to efficiently build animations, so here you go!

I will be using the GreenSock Animation Platform (GSAP). It provides a simple, readable API and solves cross-browser inconsistencies so that you can focus on animating. The code and concepts should be understandable even if you’ve never used GSAP. If you’d like to familiarize yourself with the basics of GSAP first so that you can get the most out of this article, the best place to begin is GSAP’s getting started page (includes a video). 

Tip #1: Use an animation library

Some developers think that using an animation library is wasteful because they can just use native browser technologies like CSS transitions, CSS animations or the Web Animations API (WAAPI) to accomplish the same thing without loading a library. In some cases, that’s true. However, here are a few other factors to consider:

  • Browser bugs, inconsistencies, and compatibility: An animation library, like GSAP, solves these for you and is universally compatible. You can even use motion paths in IE9! There are many problematic areas when it comes to cross-browser issues, including handling transform-origin on SVG elements, path stroke measurements, 3D origins in Safari, and many more that we don’t have the space to list.
  • Animation workflow: Building even moderately complex animations is much faster and more fun with a tool like GSAP. You can modularize animations, nest them as deeply as you want, and have their timing adjusted automatically. This makes it so much easier to experiment. Trust me: once you try building an animation sequence in CSS and then in GSAP, you’ll see what I mean. Night and day! Future edits are faster too.
  • Animate beyond the DOM: Canvas, WebGL, generic objects, and complex strings can’t be animated with native technologies. Using one consistent tool for all your animations is much cleaner. 
  • Runtime control: Using a good animation library can enable you to pause, resume, reverse, seek through, or even gradually change the speed of an entire animation sequence. You can control each transform component independently (rotation, scale, x, y, skew, etc.). You can also retrieve those values at any time as well. JavaScript animations give you ultimate flexibility.
  • Easing options (bounce, elastic, etc.): CSS only gives you two control points for eases. GSAP’s CustomEase lets you literally create any ease you can imagine. 
  • Lag smoothing: GSAP can prioritize absolute timing or adjust things on the fly to avoid jumps if the CPU gets bogged down.
  • Advanced capabilities: Using GSAP, it’s easy to morph SVGs, add physics/inertia, edit motion paths directly in the browser, use position-aware staggers, and more.

Most of the top animators in the industry use a tool like GSAP because they’ve learned these same things over the years. Once you get beyond very basic animations, a JavaScript library will make your life much, much easier and open up entirely new possibilities. 

Tip #2: Use timelines

A good animation library will provide some way of creating individual animations (called tweens) and a way to sequence animations in a timeline. Think of a timeline like a container for your tweens where you position them in relation to one another. 

const tl = gsap.timeline();".box", { duration: 1, x: 100 }) .to(".box", { duration: 1, backgroundColor: "#f38630" }, "+=0.5") .to(".box", { duration: 1, x: 0, rotation: -360 }, "+=0.5")

By default in GSAP, tweens added to a timeline will wait for the previous tweens to complete before running. The +=0.5 adds an additional offset or delay of a half-second as well, so the second tween will start 0.5 seconds after the first tween finishes no matter how long the first tween’s duration is.

To increase the amount of time between the tween to 1 second, all you need to do is change the +=0.5 to +=1! Super easy. With this approach, you can iterate on your animations quickly without worrying about doing the math to combine previous durations.

Tip #3: Use relative values

By “relative values” I mean three things:

  1. Animate values relative to their current value. GSAP recognizes += and -= prefixes for this. So x: "+=200" will add 200 units (usually pixels) to the current x. And x: "-=200" will subtract 200 from the current value. This is also useful in GSAP’s position parameter when positioning tweens relative to one another.
  2. Use relative units (like vw, vh and, in some cases, %) when values need to be responsive to viewport size changes.
  3. Use methods like .to() and .from() (instead of .fromTo()) whenever possible so that the start or end values are dynamically populated from their current values. That way, you don’t need to declare start and end values in every tween. Yay, less typing! For example, if you had a bunch of differently-colored elements, you could animate them all to black like".class", {backgroundColor: "black" }).
Tip #4: Use keyframes

If you find yourself animating the same target over and over in a row, that’s a perfect time to use keyframes! You do so like this:".box", { keyframes: [ { duration: 1, x: 100 }, { duration: 1, backgroundColor: "#f38630", delay: 0.5 }, { duration: 1, x: 0, rotation: -360, delay: 0.5 } ]});

No timeline necessary! To space out the tweens we just use the delay property in each keyframe. (It can be negative to create overlaps.)

Tip #5: Use smart defaults

GSAP has default values for properties like ease ("power1.out") and duration (0.5 seconds). So, the following is a valid tween that will animate for half a second.".box", { color: "black" })

To change GSAP’s global defaults, use gsap.defaults():

// Use a linear ease and a duration of 1 instead gsap.defaults({ ease: "none", duration: 1 });

This can be handy, but it’s more common to set defaults for a particular timeline so that it affects only its children. For example, we can avoid typing duration: 1 for each of the sub-tweens by setting a default on the parent timeline:

const tl = gsap.timeline({ defaults: { duration: 1 } });".box", { x: 100 }) .to(".box", { backgroundColor: "#f38630" }, "+=0.5") .to(".box", { x: 0, rotation: -360 }, "+=0.5") Tip #6: Animate multiple elements at once

We mentioned this briefly in the third tip, but it deserves its own tip.

If you have multiple elements that share the same class of .box, the code above will animate all of the elements at the same time!

You can also select multiple elements with different selectors by using a more complex selector string:".box, .circle", { ... });

Or you can pass an array of variable references as long as the elements are of the same type (selector string, variable reference, generic object, etc.):

var box = document.querySelector(".box"); var circle = document.querySelector(".circle"); // some time later…[box, circle], { ... }); Tip #7: Use function-based values, staggers, and/or loops Function-based values

Use a function instead of a number/string for almost any property, and GSAP will call that function once for each target when it first renders the tween. Plus, it’ll use whatever gets returned by the function as the property value! This can be really handy for creating a bunch of different animations using a single tween and for adding variance.

GSAP will pass the following parameters into the function:

  1. The index
  2. The specific element being affected
  3. An array of all of the elements affected by the tween

For example, you could set the movement direction based on the index:

Or you could choose items from an array:


Make your animations look more dynamic and interesting by offsetting the start times with a stagger. For simple staggered offsets in a single tween, just use stagger: 0.2 to add 0.2 seconds between the start time of each animation.

You can also pass in an object to get more complex stagger effects, including ones that emanate outward from the center of a grid or randomize the timings:

CodePen Embed Fallback

For more information about GSAP’s staggers, check out the stagger documentation.


It can be helpful to loop through a list of elements to create or apply animations, particularly when they are based on some event, like a user’s interaction (which I’ll discuss later on). 

To loop through a list of items, it’s easiest to use .forEach(). But since this isn’t supported on elements selected with .querySelectorAll() in IE, you can use GSAP’s utils.toArray() function instead.

In the example below, we are looping through each container to add animations to its children that are scoped to that container.

Tip #8: Modularize your animations

Modularization is one of the key principles of programming. It allows you to build small, easy-to-understand chunks that you can combine into larger creations while still keeping things clean, reusable, and easy to modify. It also lets you to use parameters and function scope, increasing the re-usability of your code.


Use functions to return tweens or timelines and then insert those into a master timeline:

function doAnimation() { // do something, like calculations, maybe using arguments passed into the function // return a tween, maybe using the calculations above return".myElem", { duration: 1, color: "red"}); } tl.add( doAnimation() );

Nesting timelines can truly revolutionize the way you animate. It lets you sequence really complex animations with ease while keeping your code modular and readable.

function doAnimation() { const tl = gsap.timeline();;; // many animations as you’d like! // When you’re all done, return the timeline return tl; } const master = gsap.timeline(); master.add( doAnimation() ); master.add( doAnotherAnimation() ); // Add even more timelines!

Here’s a real-world use case modified from Carl Schooff’s “Writing Smarter Animation Code” post.

Here’s a more complex demo showing the same technique using a Star Wars theme by Craig Roblewsky:

CodePen Embed Fallback

Wrapping your animation-building routines inside functions also makes recreating animations (say, on resize) a breeze!

var tl; // keep an accessible reference to our timeline function buildAnimation() { var time = tl ? tl.time() : 0; // save the old time if it exists // kill off the old timeline if it exists if (tl) { tl.kill(); } // create a new timeline tl = gsap.timeline(); .to(...); // do your animation tl.time(time); // set the playhead to match where it was } buildAnimation(); //kick things off window.addEventListener("resize", buildAnimation); // handle resize

If you find yourself repeating the same code and switching out one variable for another that’s usually a sign you should make a general function or use a loop instead in order to keep your code DRY (Don’t Repeat Yourself).


With effects, you can turn a custom animation into a named effect that can be called anytime with new targets and configurations. This is especially helpful when you have standards for your animations or if you are going to be calling the same animation from different contexts.

Here’s a super-simple “fade” effect to show the concept:

// register the effect with GSAP: gsap.registerEffect({ name: "fade", defaults: {duration: 2}, //defaults get applied to the "config" object passed to the effect below effect: (targets, config) => { return, {duration: config.duration, opacity:0}); } }); // now we can use it like this: gsap.effects.fade(".box"); // Or override the defaults: gsap.effects.fade(".box", {duration: 1}); Tip #9: Use control methods

GSAP provides many methods to control the state of a tween or timeline. They include .play(), .pause(), .reverse(), .progress(), .seek(), .restart(), .timeScale(), and several others. 

Using control methods can make transitions between animations more fluid (such as being able to reverse part way through) and more performant (by reusing the same tween/timeline instead of creating new instances each time). And by giving you finer control over the state of the animation, it can help with debugging as well.

Here’s a simple example:

One amazing use case is tweening the timeScale of a timeline!

CodePen Embed Fallback Use case: interaction events that trigger animations

Inside of event listeners for user interaction events, we can use control methods to have fine control over our animation’s play state.

In the example below, we are creating a timeline for each element (so that it doesn’t fire the same animation on all instances), attaching a reference for that timeline to the element itself, and then playing the relevant timeline when the element is hovered, reversing it when the mouse leaves.

CodePen Embed Fallback Use case: Animating between multiple states of a timeline

You may want a set of animations to affect the same properties of the same elements, but only in certain sequences (e.g. active/inactive states, each with mouseover/mouseout states). It may get tricky to manage. We can simplify it by using states of a timeline and control events. 

Use case: Animating based on the scroll position

We can easily fire animations based on the scroll position by using control methods. For example, this demo plays a full animation once a scroll position has been reached:

You can also attach the progress of an animation to the scroll position for more fancy scroll effects!

But if you’re going to do this, it’s best to throttle the scroll listener for performance reasons:

Hot tip: GreenSock is working on a plugin to make scroll-based animations even easier! You’re in for quite a treat. Keep your eyes peeled for news.

Bonus tip: Use GSAP’s plugins, utility methods, and helper functions

GSAP plugins add extra capabilities to GSAP’s core. Some plugins make it easier to work with rendering libraries, like PixiJS or EaselJS, while other plugins add superpowers like morphing SVG, drag and drop functionality, etc. This keeps the GSAP core relatively small and lets you add features when you need them.


MorphSVG morphs between any two SVG shapes, no matter the number of points, and gives you fine control over how the shapes are morphed.

CodePen Embed Fallback

DrawSVG progressively reveals (or hides) the stroke of an SVG element, making it look like it’s being drawn. It works around various browser bugs that affect typical stroke-dashoffset animations.

MotionPath animates anything (SVG, DOM, canvas, generic objects, whatever) along a motion path in any browser. You can even edit the path in-browser using MotionPathHelper!

CodePen Embed Fallback

GSDevTools gives you a visual UI for interacting with and debugging GSAP animations, complete with advanced playback controls, keyboard shortcuts, global synchronization and more.

CodePen Embed Fallback

Draggable provides a surprisingly simple way to make virtually any DOM element draggable, spinnable, tossable, or even flick-scrollable using mouse or touch events. Draggable integrates beautifully (and optionally) with InertiaPlugin so the user can flick and have the motion decelerate smoothly based on momentum.

CodePen Embed Fallback

CustomEase (along with CustomBounce and CustomWiggle) add to GSAP’s already extensive easing capabilities by enabling you to register any ease that you’d like.

SplitText is an easy to use JavaScript utility that allows you to split HTML text into characters, words and lines. It’s easy to use, extremely flexible, works all the way back to IE9, and handles special characters for you.

CodePen Embed Fallback

ScrambleText scrambles the text in a DOM element with randomized characters, refreshing new randomized characters at regular intervals, while gradually revealing your new text (or the original) over the course of the tween. Visually, it looks like a computer decoding a string of text.

CodePen Embed Fallback

Physics2D lets you tween the position of elements based on velocity and acceleration as opposed to going to specific values. PhysicsProps is similar but works with any property, not just 2D coordinates.

CodePen Embed Fallback Utility methods

GSAP has built-in utility methods that can make some common tasks easier. Most are focused on manipulating values in a particular way, which can be especially helpful when generating or modifying animation values. The ones that I use most often are .wrap(), .random, .interpolate(), .distribute(), .pipe(), and .unitize(), but there are many others you might find helpful.

Helper functions

In a similar light, but not built into GSAP’s core, are some helper functions GreenSock has created over the years to deal with specific use cases. These functions make it easy to FLIP your animations, return a random number based on an ease curve, blend two ease curves, and much more. I highly recommend checking them out!


You’ve made it to the end! Hopefully, you’ve learned a thing or two along the way and this article will continue to be a resource for you in the years to come.

As always, if you have any questions about GSAP, feel free to drop by the GreenSock forums. They’re incredibly helpful and welcoming! As an employee of GreenSock, that’s where I hang out often; I love helping people with animation-related challenges!

The post Tips for Writing Animation Code Efficiently appeared first on CSS-Tricks.

CSS Foldable Display Polyfill

Css Tricks - Thu, 04/09/2020 - 4:51am

Foldable phones are starting to be a thing. Early days, for sure, but some are already shipping, and they definitely have web browsers on them. Stands to reason that, as web designers, we are going to want to know where that fold is so we can design screens that fit onto the top half and bottom half… or left half and right half¹.

Looks like that’s going to make its way to us in the form of env() constants, just like all that notch stuff.

The code block in the polyfill repo is:

@media (spanning: single-fold-vertical) { body { flex-direction: row; } .map { flex: 1 1 env(fold-left) } .locations-list { flex: 1; } }

I would also think it could be…

@media (spanning: single-fold-vertical) { .page-wrap { display: grid; grid-template-columns: env(fold-left) 1fr; } }

Interesting how there is no fold-right, isn’t it? And aren’t we trying to stay away from directional terms like that and use logical properties? Why not fold-inline-start?

  1. It’ll be interesting to see how that sentence ages. Just watch the first really popular foldable phone will have three segments.

The post CSS Foldable Display Polyfill appeared first on CSS-Tricks.

Create Diagonal Layouts Like it’s 2020

Css Tricks - Thu, 04/09/2020 - 4:44am

Nils Binder covers the ways:

1. Use an SVG in the form of a triangle. This technique is nicely described by Erik Kennedy on CSS-Tricks.

2. Hide part of your section using clip-path. Read Diagonal Containers in CSS by Sebastiano Guerriero or Sloped edges with consistent angle in CSS by Kilian Valkhof.

3. Using CSS Transforms

I would normally be a #2 kinda guy — slice off the top and bottom a bit, make sure there is ample padding, and call it a day. But Nils almost has me convinced this fancy math is better.

Here’s a kinda dumb clip-path way:

CodePen Embed Fallback

And Nils incredibly fancy playground:

CodePen Embed Fallback

Direct Link to ArticlePermalink

The post Create Diagonal Layouts Like it’s 2020 appeared first on CSS-Tricks.

Learn Eleventy From Scratch

Css Tricks - Tue, 04/07/2020 - 6:35am

The latest edition of Andy Bell’s Piccalilli landed in my inbox this morning with a sweet offer: preorder Andy’s course on learning Eleventy from scratch at a third of the price.

Why the plug? No, not sponsorships or anything like that. I just happen to hear a heckuva lot about Eleventy these days. Like how we can use it with Google Sheets as a pseudo-CMS. Or how it can be a key component of an emergency website kit. I mean, geez, Chris even used it for the conferences site we have around here. As Andy says, “the future is bright because the future is static.” At least, it certainly appears that way.

I’m squarely in the novice camp when it comes to Eleventy, not to mention static site generators as a whole. That’s why I signed up for the course. It promises to be a deep dive that starts with an empty directory and goes all the way to full-blown website. Given that Andy has created more Eleventy sites than most folks (seriously, it’s documented) and that his Eleventy-powered Piccalilli site notches perfect Lighthouse scores, I think he’ll have a lot to offer in a course.

While we’re on the topic of Eleventy, there are other guides, tutorials and courses out there you might find compelling:

Direct Link to ArticlePermalink

The post Learn Eleventy From Scratch appeared first on CSS-Tricks.

How to Re-Create a Nifty Netflix Animation in CSS

Css Tricks - Tue, 04/07/2020 - 4:51am

The design for Netflix’s browse page has remained pretty similar for a few years now. One mainstay component is the preview slider that allows users to scroll through content and hover on items to see a preview.

One unique characteristic of the UI is its hover behavior. When a show preview expands on hover, the cards next to it are pushed outward so that they don’t overlap. 

Like this:

It’s like Bill Murray and Brad Pitt are fighting for the spotlight.

We can do this in CSS! No JavaScript. No dependencies. Plain CSS. But before getting into any code, here’s exactly what we want to do:

  1. The card that is hovered over should expand while keeping its aspect ratio.
  2. When a card is hovered, the other cards should not change size and move outwards so that they don’t overlap one another.
  3. All the cards should remain vertically centered with one another.

Sound good? Now let’s get into the code.

HTML and flexible elements

Let’s set up a row of images that represents Netflix’s video previews. That includes:

  • A  .container parent element with several .item elements inside
  • Each .item element consisting of an image wrapped in an anchor tag
  • Turning .container into a flex container that aligns the items in a row
  • Setting the flex behavior for the .item class so they take up equal space in the row
CodePen Embed Fallback Expanding an item on hover

Our next step is getting an item to expand when it is hovered. We could do this by animating the element’s width, but that would affect the flow of the document and cause the hovered item’s siblings to shrink – plus, animating the width property is known to be poor for performance in some cases.

To avoid squeezing the sibling of the hovered item, we are going to animate the transform property — specifically, its scale() function — instead. This won’t affect document flow the same way width does.

CodePen Embed Fallback Moving siblings outward

Getting the siblings of a hovered item to move away from the hovered item is the tricky part of this whole thing. One CSS feature we have at our disposal is the general sibling combinator. This lets us select all of the sibling items that are positioned after the hovered item.

We’ll turn to the transform property’s translateX() function to move things around. Again, animating transform is much nicer than other properties that impact document flow, like margins and padding.

Since we’ve set an item to scale up 150% on hover, the translation should be set to 25%. That’s half of the additional space that is being occupied by the hovered item.

.item:hover ~ .item {   transform: translateX(25%); }

That handles moving things to the right, but how can we translate the items on the left? Since the general sibling combinator only applies to siblings positioned after a given selector (no going “backwards”), we’ll need another approach.

One way is to add an additional hover rule on the parent container itself. Here is the plan:

  • When hovering the parent container, shift all the items inside that container to the left.
  • Use the general sibling combinator to make the items positioned after the hovered item move to the right.
  • Get super specific so a hovered item isn’t translated like the rest of the items.

We’re making a big assumption that your document uses a left-to-right writing mode. If you want to use this effect in a right-to-left context, you will need to set all items inside the hovered outer container to move right and use the general sibling combinator to move all selected items left.

Demo time! CodePen Embed Fallback

One little thing to note: this final version is using :focus and :focus-within pseudo-classes to support keyboard navigation. The Netflix example isn’t using it, but I think that’s a nice touch for accessibility.

There we have it! Yes, we could have used JavaScript event listeners instead of CSS hover rules., and that could possibly be better for maintainability and readability. But it’s sometimes fun to see just how far CSS can take us!

The post How to Re-Create a Nifty Netflix Animation in CSS appeared first on CSS-Tricks.

CSS Findings From The New Facebook Design

Css Tricks - Tue, 04/07/2020 - 4:51am

Ahmad Shadeed digs around the new Facebook’s front-end code.

One that stood out to me:

.element { inset: 4px 0; /* Which is equivalent to: top: 4px, bottom: 4px, left: 0, right: 0 */ }

Whaaat? This is the first I’ve heard of the inset property. Ahmad said he saw it working in Chrome 80, but it definitely isn’t for me (nor Safari). It does in Firefox though.

Chrome 80 and Firefox 75

It’s shorthand for top/right/bottom/left (just like margin, in a sense), which is certainly welcome if you ask me. Bring on the support.

If you’re into people digging into big sites to learn stuff…

Direct Link to ArticlePermalink

The post CSS Findings From The New Facebook Design appeared first on CSS-Tricks.

A Grid of Logos in Squares

Css Tricks - Mon, 04/06/2020 - 11:22am

Let’s build a literal grid of squares, and we’ll put the logos of some magazines centered inside each square. I imagine plenty of you have had to build a logo grid before. You can probably already picture it: an area of a site that lists the donors, sponsors, or that is showing off all the big fancy companies that use some product. Putting the logos into squares is a decent way of handling it, as it forces some clean structure amongst logos that are all different sizes, aspect ratios, and visual weights, which can get finicky and look sloppy.

By “grid” I mean CSS grid. Setting up a grid of (flexible) squares is a little trick of its own. Then we’ll plop those logos in there in a way that keeps them sized and centered. At the end, we’ll look at one little oddity.

1) Grid markup

Have you ever tried this in an editor that supports Emmet?


Then press tab. It will expand out into:

<div class="grid"> <div><img src="" alt=""></div> <div><img src="" alt=""></div> <div><img src="" alt=""></div> <div><img src="" alt=""></div> <div><img src="" alt=""></div> </div>

Just a little trick for working quickly.

2) CSS Grid basics

We’ll use the infamous flexible columns technique:

.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-gap: 1rem; }

That will give us not only flexible columns, but a flexible number of columns. Remember, we don’t really care how many columns there are — we’re just building a grid of logos to display.

If we give each of those grid item divs a background and a forced height, we’d see something like:

This screenshot is at a parent width of about 800px. The three columns seen here will increase and decrease to fill the space, thanks to that grid magic. 2) Making real squares

Rather than force the grid items to any particular height, let’s use an aspect-ratio trick. We’ll plop an empty pseudo-element in there with padding-bottom: 100%; meaning it will force the height to be at least as tall as it is wide.

.grid > div { background: black; padding: 1rem; } .grid > div::before { content: ""; padding-bottom: 100%; display: block; }

If we temporarily hide the images, you’ll see the grid of rectangles has become a grid of perfect squares:

3) Overlapping the Images

But with the images in there, they grow a little oblong because the image sits in the pseudo-element.

We’ll need a way to sit them on top of one another. Usually, with aspect-ratio techniques, we reach for absolute positioning to place the in-child container to cover the now aspect-ratioed shape. But since we’re using grid already anyway, let’s use grid again to place the items into the same space:

.grid > div { /* ... */ display: grid; } .grid > div::before, .grid > div > img { grid-area: 1 / 1 / 2 / 2; }

That says to make the grid items of the main grid also into grid containers, with no explicit rows and columns, then to place both the pseudo-element and image onto the first row and column of that grid. This will force them to overlap them, making a nice grid of squares again.

4) Placing the images

Let’s plop a proper src in there for each image. If we make sure the images fill the space (and limit themselves) with width: 100%, we’ll see them along the top of the grid items:

Not terrible, but we would prefer to see them centered. Here’s one trick to do that. First, we’ll also make their height: 100%, which distorts them:

Then fix that up with object-fit!

.grid > div > img { width: 100%; height: 100%; object-fit: contain; }

There we go:

That will work responsively:

5) Quirky dragging size

This (probably) isn’t a massive deal, but notice how the logos look when you drag them off (like a user might if they are trying to save one):

The images look like they have width: 100%; height: 100%; without the object-fit: contain;.

Here’s the working demo so far, with that quirk:

CodePen Embed Fallback 6) Use absolute positioning instead

If that dragging quirk is a big deal, we can always just absolutely position the images inside the grid children instead.

Here’s one way, assuming the grid child div is position: relative;:

.grid > div > img { position: absolute; max-width: 100%; top: 0; bottom: 0; right: 0; left: 0; margin: auto; }

And here’s another:

.grid > div > img { position: absolute; max-width: 100%; top: 50%; left: 50%; transform: translate(-50%, -50%); }

Either of those fix that dragging quirk. Here’s a demo:

CodePen Embed Fallback Video

If you’d like to watch a video walkthrough of all this, here ya go!

The post A Grid of Logos in Squares appeared first on CSS-Tricks.

How to Animate Text with SVG and CSS

Css Tricks - Wed, 03/25/2020 - 4:36pm

The other day I was helping my pal Jez work Dept. of Enthusiasm, the site for his newsletter, and I had a thought. What if we made the word “enthusiasm” in the title animate a little bit? Like, what if each of the letters in the word bopped up and down enthusiastically?

Like this:

CodePen Embed Fallback

Neat, huh? To build this thing I knew we could use SVG for the text and then animate things with CSS. Each letter is a path with its own class, which makes it possible to select each one. That said, there’s nothing really stopping us from doing this with HTML and CSS. Using SVG is just one approach that felt right to me at the time.

To get started we headed over to Figma and typed out the text in separate text boxes. We did this so that when we click on the “Outline stroke” menu item here...

...we have individual vectors of each letter. This will help us when we export the SVG so that we can add the correct CSS classes to each element. Once we’ve outlined the strokes of each letter we can then edit the points in the vector (but we don’t need to for what we’re about to do):

If we added all the text in one box and clicked "Outline Stroke" then it would’ve created a single vector with all these letters combined. That would then make a single path with the coordinates and that’s pretty difficult for me to style or even understand what the heck is going on in there.

Next up, I put all these letters in a Frame (Sketch calls this an Artboard) and placed each word into a Group. This way, when they’re exported as an SVG, each word will be in it's own g tag which also helps us style the letters:

From there, I exported the SVG — but! — I had to make sure to include the id option when doing it.

If we don’t do this we’ll get a bunch of path elements for each letter but they won’t have an id attributes.

This is what we get after the export:

CodePen Embed Fallback

I'm not sure how much of this weirdness is me and how much is Figma’s SVG export, but I deleted that <rect> element because it's unecessary. Then I gave the body element a background so I could see the text and remove those inline height and width attributes on the SVG itself:

CodePen Embed Fallback

Neato! Now we can get to the fun part: animating each letter in the word.

If you look at the HTML of that example above you’ll notice there's a g element which with an id with the same name of the Frame in Figma.There are also g elements for each word and every path that makes up the word will have an individual id. (This is why naming our Frames and Groups properly, as well as keeping things organized in any design application, is important.)

One thing that surprised me was the order in which each path is exported though: it’s in the opposite order than the one I’d expect, with M being the first letter in the “ENTHUSIASM” group. So I cleaned that up a bit and made sure each letter is in the correct order.

To get the animation working we first bump down each letter by 2px:

g path { transform: translateY(2px); }

That’s because I want each letter to make a 2px hop which we’ll get to in a bit. I also noticed with this change I’d need to update the SVG viewbox too. Otherwise, the bottom of each letter will be cut off:

<svg class="header" viewBox="0 0 146 13" fill="none" xmlns="">

I probably should’ve have just repositioned the text within the frame in Figma and exported it again, but this is fine for what I needed.

Now I can target the third group in the SVG (the word “enthusiasm”) and set the animation-count to infinite:

/* targets the word "enthusiasm" */ g:nth-child(3) path { animation-name: wiggleWiggle; animation-duration: 2.5s; animation-iteration-count: infinite; }

The code above then calls the wiggleWiggle animation below:

@keyframes wiggleWiggle { 20%, 100% { transform: translate(0, 2px); /* stay on the baseline for most of the animation duration */ } 0% { transform: translate(0, 0px); /* hop up */ } 10% { transform: translate(0, 2px); /* return to baseline */ } }

See the beginning of that keyframe — the 20%, 100% bit? What that's saying is "keep all the text on the baseline for the majority of the animation." That’s what gives us a nice delay between each bounce:

CodePen Embed Fallback

I learnt this trick from this really good post about animation timing by Geoff and I would highly recommend you check it out if you’re about to start learning about animation in CSS.

Now for the fun bit: with the animation-delay property, we can make each letter hop just after the one before it. There’s definitely a smarter way I could be doing this, but I just used the id of each letter like so:

#E { animation-delay: 0s; } #N { animation-delay: 0.1s; } #T { animation-delay: 0.15s; } #H { animation-delay: 0.2s; } #U { animation-delay: 0.25s; } #S_2 { animation-delay: 0.3s; } #I { animation-delay: 0.35s; } #A { animation-delay: 0.4s; } #S { animation-delay: 0.45s; } #M { animation-delay: 0.5s; }

It sure is messy, but writing the loop wouldn’t save me that much time and I won’t need to update it in the future, so I think it’s fine enough. And with that we’re pretty much done!

CodePen Embed Fallback

We now have a bouncy, enthusiastic title to say hello. Yay for wiggly text!

The post How to Animate Text with SVG and CSS appeared first on CSS-Tricks.

CSS Viewport Units

Css Tricks - Wed, 03/25/2020 - 4:35pm

Deep dive from Ahmad. I like the coverage of vmin and vmax, which I think I don't reach for as often as I should.

I'm thinking that if you are doing something highly directional (e.g. a full bleed trick), then directly using vw is necessary. On the other hand, if you're doing a calculation where the goal is to generally factor in viewport size (like fluid margins/gaps or fluid type) that using vmin might be more appropriate. For example, if a user has a browser window that is currently quite wide, but very short, they probably don't need massive header text like a vw-only calculation might come up with.

Direct Link to ArticlePermalink

The post CSS Viewport Units appeared first on CSS-Tricks.

An Introduction to MDXJS

Css Tricks - Wed, 03/25/2020 - 5:10am

Markdown has traditionally been a favorite format for programmers to write documentation. It’s simple enough for almost everyone to learn and adapt to while making it easy to format and style content. It was so popular that commands from Markdown have been used in chat applications like Slack and Whatsapp as document applications, like Dropbox Paper and Notion. When GitHub introduced Markdown support for README documentation, they also rendered HTML content from it — so, for example, we could drop in some link and image elements and they would render just fine.

Even though Markdown isn’t broken by any stretch of the imagination, there’s always room for improvement. This is where Markdown Extended (MDX) comes in.

When would we consider MDX over Markdown? One thing about MDX is that JavaScript can be integrated into cases where normal Markdown is used. Here are few examples that illustrate how handy that is:

  • Frontend Armory uses MDX on its education playground, Demoboard. The playground supports MDX natively to create pages that serve both as demo and documentation, which is super ideal for demonstrating React concepts and components.
  • Brent Jackson has a brand new way of building websites pairing MDX and Styled System. Each page is written in MDX and Styled System styles the blocks. It’s currently in development, but you can find more details on the website.
  • Using mdx-deck or Spectacle could make your next presentation more interesting. You can show demos directly in your deck without switching screens!
  • MDX Go, ok-mdx and Docz all provide tools for documenting component libraries in MDX. You can drop components right in the documentation with Markdown and it will just work™.
  • Some sites, including Zeit Now and Prisma docs, use MDX to write content.

MDX shines in cases where you want to maintain a React-based blog. Using it means you no longer have to create custom React component pages when you want to do something impossible in Markdown (or create a plugin). I have been using it on my blog for over a year and have been loving the experience One of my favorite projects so far is a React component I call Playground that can be used to demo small HTML/CSS/JavaScript snippets while allowing users to edit the code. Sure, I could have used some third-party service and embed demos with it, but this way I don’t have to load third-party scripts at all.

Speaking of embedding, MDX makes it so easy to embed iFrames created by third-party services, say YouTube, Vimeo, Giphy, etc.

Use it alongside Markdown

You’ll know a file is written in MDX because it has an .mdx extension on the filename. But let’s check out what it looks like to actually write something in MDX.

import InteractiveChart from "../path/interactive-chart"; ? # Hello - I'm a Markdown heading ? This is just markdown text ? <InteractiveChart />

See that? It’s still possible to use Markdown and we can write it alongside React components when we want interactive visualizations or styling. Here is an example from my portfolio:

Another benefit of MDX is that, just like components, the files are composable. This means that pages can be split into multiple chunks and reused, rendering them all at once.

import Header from "./path/Header.mdx" import Footer from "./path/Footer.mdx" <Header /> # Here goes the actual content. Some random content goes [here](link text) <Footer /> Implementing MDX into apps

There are MDX plugins for most of the common React based integration platforms, like Gatsby and Next

To integrate it in a create-react-app project, MDX provides a Babel Macro that can be imported into the app:

import { importMDX } from './mdx.macro' const MyDocument = React.lazy(() => importMDX('./my-document.mdx')) ReactDOM.render( <React.Suspense fallback={<div>Loading...</div>}> <MyDocument /> </React.Suspense>, document.getElementById('root') );

You can also try out MDX on the playground they created for it.

MDX contributors are very actively working on bringing support for Vue. A sample is already available on GitHub. This is though in Alpha and not ready for production.

Editor support

Syntax highlighting and autocomplete have both been increasing support for VS CodeVim, and Sublime Text. However, in use, these do have some sharp edges and are difficult to navigate. A lot of these come from the inability to predict whether we are going for JavaScript or Markdown within the context of a page. That’s something that certainly can be improved.

MDX plugins and extensions

A key advantage of MDX is that it is part of the unified consortium for content that organizes remark content. This means that MDX can directly support the vast ecosystem of remark plugins and rehype plugins — there’s no need to reinvent the wheel. Some of these plugins, including remark-images and remark-redact, are remarkable, to say the least. To use a plugin with MDX, you can add them to your corresponding loader or plugin. You can even write your own MDX plugins by referring to the MDX Guide for creating plugins.

MDX is only a few years old but its influence has been growing in the content space. From writing blog posts and visualizing data to creating interactive demos and decks, MDX is well suited for many uses — well beyond what we have covered here in this introduction.

The post An Introduction to MDXJS appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.