Tag: Little

A Handy Little System for Animated Entrances in CSS

I love little touches that make a website feel like more than just a static document. What if web content wouldn’t just “appear” when a page loaded, but instead popped, slid, faded, or spun into place? It might be a stretch to say that movements like this are always useful, though in some cases they can draw attention to certain elements, reinforce which elements are distinct from one another, or even indicate a changed state. So, they’re not totally useless, either.

So, I put together a set of CSS utilities for animating elements as they enter into view. And, yes, this pure CSS. It not only has a nice variety of animations and variations, but supports staggering those animations as well, almost like a way of creating scenes.

You know, stuff like this:

Which is really just a fancier version of this:

We’ll go over the foundation I used to create the animations first, then get into the little flourishes I added, how to stagger animations, then how to apply them to HTML elements before we also take a look at how to do all of this while respecting a user’s reduced motion preferences.

The basics

The core idea involves adding a simple CSS @keyframes animation that’s applied to anything we want to animate on page load. Let’s make it so that an element fades in, going from opacity: 0 to opacity: 1 in a half second:

.animate {   animation-duration: 0.5s;   animation-name: animate-fade;   animation-delay: 0.5s;   animation-fill-mode: backwards; }  @keyframes animate-fade {   0% { opacity: 0; }   100% { opacity: 1; } }

Notice, too, that there’s an animation-delay of a half second in there, allowing the rest of the site a little time to load first. The animation-fill-mode: backwards is there to make sure that our initial animation state is active on page load. Without this, our animated element pops into view before we want it to.

If we’re lazy, we can call it a day and just go with this. But, CSS-Tricks readers aren’t lazy, of course, so let’s look at how we can make this sort of thing even better with a system.

Fancier animations

It’s much more fun to have a variety of animations to work with than just one or two. We don’t even need to create a bunch of new @keyframes to make more animations. It’s simple enough to create new classes where all we change is which frames the animation uses while keeping all the timing the same.

There’s nearly an infinite number of CSS animations out there. (See animate.style for a huge collection.) CSS filters, like blur(), brightness() and saturate() and of course CSS transforms can also be used to create even more variations.

But for now, let’s start with a new animation class that uses a CSS transform to make an element “pop” into place.

.animate.pop {   animation-duration: 0.5s;   animation-name: animate-pop;   animation-timing-function: cubic-bezier(.26, .53, .74, 1.48); }  @keyframes animate-pop {   0% {     opacity: 0;     transform: scale(0.5, 0.5);   }    100% {     opacity: 1;     transform: scale(1, 1);   } }

I threw in a little cubic-bezier() timing curve, courtesy of Lea Verou’s indispensable cubic-bezier.com for a springy bounce.

Adding delays

We can do better! For example, we can animate elements so that they enter at different times. This creates a stagger that makes for complex-looking motion without a complex amount of code.

This animation on three page elements using a CSS filter, CSS transform, and staggered by about a tenth of a second each, feels really nice:

All we did there was create a new class for each element that spaces when the elements start animating, using animation-delay values that are just a tenth of a second apart.

.delay-1 { animation-delay: 0.6s; }   .delay-2 { animation-delay: 0.7s; } .delay-3 { animation-delay: 0.8s; }

Everything else is exactly the same. And remember that our base delay is 0.5s, so these helper classes count up from there.

Respecting accessibility preferences

Let’s be good web citizens and remove our animations for users who have enabled their reduced motion preference setting:

@media screen and (prefers-reduced-motion: reduce) {   .animate { animation: none !important; } }

This way, the animation never loads and elements enter into view like normal. It’s here, though, that is worth a reminder that “reduced” motion doesn’t always mean “remove” motion.

Applying animations to HTML elements

So far, we’ve looked at a base animation as well as a slightly fancier one that we were able to make even fancier with staggered animation delays that are contained in new classes. We also saw how we can respect user motion preferences at the same time.

Even though there are live demos that show off the concepts, we haven’t actually walked though how to apply our work to HTML. And what’s cool is that we can use this on just about any element, whether its a div, span, article, header, section, table, form… you get the idea.

Here’s what we’re going to do. We want to use our animation system on three HTML elements where each element gets three classes. We could hard-code all the animation code to the element itself, but splitting it up gives us a little animation system we can reuse.

  • .animate: This is the base class that contains our core animation declaration and timing.
  • The animation type: We’ll use our “pop” animation from before, but we could use the one that fades in as well. This class is technically optional but is a good way to apply distinct movements.
  • .delay-<number>: As we saw earlier, we can create distinct classes that are used to stagger when the animation starts on each element, making for a neat effect. This class is also optional.

So our animated elements might now look like:

<h2 class="animate pop">One!</h2> <h2 class="animate pop delay-1">Two!</h2> <h2 class="animate pop delay-2">Three!</h2>

Let’s count them in!

Conclusion

Check that out: we went from a seemingly basic set of @keyframes and turned it into a full-fledged system for applying interesting animations for elements entering into view.

This is ridiculously fun, of course. But the big takeaway for me is how the examples we looked at form a complete system that can be used to create a baseline, different types of animations, staggered delays, and an approach for respecting user motion preferences. These, to me, are all the ingredients for a flexible system that easy to use, while giving us a lot with a little and without a bunch of extra cruft.

What we covered could indeed be a full animation library. But, of course, I did’t stop there and have my entire CSS file of animations in all its glory for you. There are several more types of animations in there, including 15 classes of different delays that can be used for staggering things. I’ve been using these on my own projects, but it’s still an early draft and I love feedback on it—so please enjoy and let me know what you think in the comments!

/* ========================================================================== Animation System by Neale Van Fleet from Rogue Amoeba ========================================================================== */ .animate {   animation-duration: 0.75s;   animation-delay: 0.5s;   animation-name: animate-fade;   animation-timing-function: cubic-bezier(.26, .53, .74, 1.48);   animation-fill-mode: backwards; }  /* Fade In */ .animate.fade {   animation-name: animate-fade;   animation-timing-function: ease; }  @keyframes animate-fade {   0% { opacity: 0; }   100% { opacity: 1; } }  /* Pop In */ .animate.pop { animation-name: animate-pop; }  @keyframes animate-pop {   0% {     opacity: 0;     transform: scale(0.5, 0.5);   }   100% {     opacity: 1;     transform: scale(1, 1);   } }  /* Blur In */ .animate.blur {   animation-name: animate-blur;   animation-timing-function: ease; }  @keyframes animate-blur {   0% {     opacity: 0;     filter: blur(15px);   }   100% {     opacity: 1;     filter: blur(0px);   } }  /* Glow In */ .animate.glow {   animation-name: animate-glow;   animation-timing-function: ease; }  @keyframes animate-glow {   0% {     opacity: 0;     filter: brightness(3) saturate(3);     transform: scale(0.8, 0.8);   }   100% {     opacity: 1;     filter: brightness(1) saturate(1);     transform: scale(1, 1);   } }  /* Grow In */ .animate.grow { animation-name: animate-grow; }  @keyframes animate-grow {   0% {     opacity: 0;     transform: scale(1, 0);     visibility: hidden;   }   100% {     opacity: 1;     transform: scale(1, 1);   } }  /* Splat In */ .animate.splat { animation-name: animate-splat; }  @keyframes animate-splat {   0% {     opacity: 0;     transform: scale(0, 0) rotate(20deg) translate(0, -30px);     }   70% {     opacity: 1;     transform: scale(1.1, 1.1) rotate(15deg));   }   85% {     opacity: 1;     transform: scale(1.1, 1.1) rotate(15deg) translate(0, -10px);   }    100% {     opacity: 1;     transform: scale(1, 1) rotate(0) translate(0, 0);   } }  /* Roll In */ .animate.roll { animation-name: animate-roll; }  @keyframes animate-roll {   0% {     opacity: 0;     transform: scale(0, 0) rotate(360deg);   }   100% {     opacity: 1;     transform: scale(1, 1) rotate(0deg);   } }  /* Flip In */ .animate.flip {   animation-name: animate-flip;   transform-style: preserve-3d;   perspective: 1000px; }  @keyframes animate-flip {   0% {     opacity: 0;     transform: rotateX(-120deg) scale(0.9, 0.9);   }   100% {     opacity: 1;     transform: rotateX(0deg) scale(1, 1);   } }  /* Spin In */ .animate.spin {   animation-name: animate-spin;   transform-style: preserve-3d;   perspective: 1000px; }  @keyframes animate-spin {   0% {     opacity: 0;     transform: rotateY(-120deg) scale(0.9, .9);   }   100% {     opacity: 1;     transform: rotateY(0deg) scale(1, 1);   } }  /* Slide In */ .animate.slide { animation-name: animate-slide; }  @keyframes animate-slide {   0% {     opacity: 0;     transform: translate(0, 20px);   }   100% {     opacity: 1;     transform: translate(0, 0);   } }  /* Drop In */ .animate.drop {    animation-name: animate-drop;    animation-timing-function: cubic-bezier(.77, .14, .91, 1.25); }  @keyframes animate-drop { 0% {   opacity: 0;   transform: translate(0,-300px) scale(0.9, 1.1); } 95% {   opacity: 1;   transform: translate(0, 0) scale(0.9, 1.1); } 96% {   opacity: 1;   transform: translate(10px, 0) scale(1.2, 0.9); } 97% {   opacity: 1;   transform: translate(-10px, 0) scale(1.2, 0.9); } 98% {   opacity: 1;   transform: translate(5px, 0) scale(1.1, 0.9); } 99% {   opacity: 1;   transform: translate(-5px, 0) scale(1.1, 0.9); } 100% {   opacity: 1;   transform: translate(0, 0) scale(1, 1);   } }  /* Animation Delays */ .delay-1 {   animation-delay: 0.6s; } .delay-2 {   animation-delay: 0.7s; } .delay-3 {   animation-delay: 0.8s; } .delay-4 {   animation-delay: 0.9s; } .delay-5 {   animation-delay: 1s; } .delay-6 {   animation-delay: 1.1s; } .delay-7 {   animation-delay: 1.2s; } .delay-8 {   animation-delay: 1.3s; } .delay-9 {   animation-delay: 1.4s; } .delay-10 {   animation-delay: 1.5s; } .delay-11 {   animation-delay: 1.6s; } .delay-12 {   animation-delay: 1.7s; } .delay-13 {   animation-delay: 1.8s; } .delay-14 {   animation-delay: 1.9s; } .delay-15 {   animation-delay: 2s; }  @media screen and (prefers-reduced-motion: reduce) {   .animate {     animation: none !important;   } }

The post A Handy Little System for Animated Entrances in CSS appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , ,

So many little design helper sites!

I had one of those little single-serving designer helper sites bookmarked the other day: getwaves.io. Randomized SVG waves! Lots of cool options! Easy to customize! Easy to copy and paste! Well played, z creative labs.

But then I saw the little link at the top of the page, that it was part of something called Haikei. So I checked that out, and holy mackerel, it’s great! There are a dozen or more similar “generators” within one app, each just as well done as the SVG waves one.

Random scattering of vector stars.

Kind of reminds me of Omatsuri which is a similar collection of useful little on-off tools.

But heck, those are just two apps, even if they are collections of mini apps in an of themselves. Around the same time, I became aware of tiny-helpers.dev, which is a roundup site of all sorts of these little one-off helper sites. Haikei and Omatsuri are both on there, along with many hundred more. Just the SVG area alone is super:

I’m sure y’all find these things just as useful as I do. They don’t make us lazy, they make us efficient. I know how to make a pattern. I know how to draw a curve with a Pen Tool. I know how to convert SVG into JSX. But using a dedicated tool makes me faster and better at it. And sometimes I don’t know how to do those things, but that doesn’t mean I can’t take advantage. Fake it ’til you make it, right?


The post So many little design helper sites! appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , ,
[Top]

So many little design helper sites!

I had one of those little single-serving designer helper sites bookmarked the other day: getwaves.io. Randomized SVG waves! Lots of cool options! Easy to customize! Easy to copy and paste! Well played, z creative labs.

But then I saw the little link at the top of the page, that it was part of something called Haikei. So I checked that out, and holy mackerel, it’s great! There are a dozen or more similar “generators” within one app, each just as well done as the SVG waves one.

Random scattering of vector stars.

Kind of reminds me of Omatsuri which is a similar collection of useful little on-off tools.

But heck, those are just two apps, even if they are collections of mini apps in an of themselves. Around the same time, I became aware of tiny-helpers.dev, which is a roundup site of all sorts of these little one-off helper sites. Haikei and Omatsuri are both on there, along with many hundred more. Just the SVG area alone is super:

I’m sure y’all find these things just as useful as I do. They don’t make us lazy, they make us efficient. I know how to make a pattern. I know how to draw a curve with a Pen Tool. I know how to convert SVG into JSX. But using a dedicated tool makes me faster and better at it. And sometimes I don’t know how to do those things, but that doesn’t mean I can’t take advantage. Fake it ’til you make it, right?


The post So many little design helper sites! appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , ,
[Top]

Little Things on My Personal Site

I updated my personal website the other day. Always a fun project since it’s one of the few where it’s 100% just me. It’s my own personal playground with no other goal than making the site represent me to have a little fun. It’s not a complete re-write, just some new paint.

I thought I’d document little bits of it here just to hone in on some of the bits of trickery in the spirit of learning through sharing.

Screenshot of the entire length of the homepage of ChrisCoyier.net. Four major boxes of content: build-your-own bio in yellow, blog posts in purple, action items in red, and a video in blue.

Hoefler Fonts

I think the Inkwell family is super cool. I like mix and matching not just the weights but the serif and sans-serif and caps vs not.

From the Inkwell introduction post.

I used Inkwell in the last design as well, but I was worried that it was a little too jokey for blog post body copy. My writing is extremely casual, but not always, and Inkwell is way too jovial for serious topics. I went with Ideal Sans for body copy last time, but the pairing with Inkwell felt a little off.

This time I went with Whitney for general body copy, which is still pretty lighthearted, but works when the copy is more straight toned.

Blogroll

If you’re going to zebra-stripe a table, you’d do something like…

tr:nth-child(even) {   background-color: var(--color-1); } tr:nth-child(odd) {   background-color: var(--color-2); }

What if you wanted to rotate four colors though? It’s still :nth-child trickery, selecting every four, and then offsetting. Here, I’ll do it with list items in Sass (the nesting is nice, not having to repeat the selector):

li {   &:nth-child(4n) a {     color: $ blue;   }   &:nth-child(4n + 1) a {     color: $ yellow;   }   &:nth-child(4n + 2) a {     color: $ red;   }   &:nth-child(4n + 3) a {     color: $ purple;   } }

That’s what I did to build the colorized blogroll:

Note the Sass used above… I used Sass because it was already in use on the project. All I had to do was open CodeKit and the processing was ready-to-go.

Oh, and blogrolls are cool again.

Chill YouTube

I used this click-to-load-YouTube-(at all) technique which is still extremely clever. Having an <iframe> that behaves just like a YouTube embed would but only loading a simple static image (rather than heaps and heaps of resources) is great for performance and behaves essentially the same as a normal YouTube embed does.

<iframe   width="560"   height="315"   src="https://www.youtube.com/embed/Y8Wp3dafaMQ"   srcdoc="<style>*{padding:0;margin:0;overflow:hidden}html,body{height:100%}img,span{position:absolute;width:100%;top:0;bottom:0;margin:auto}span{height:1.5em;text-align:center;font:48px/1.5 sans-serif;color:white;text-shadow:0 0 0.5em black}</style><a href=https://www.youtube.com/embed/Y8Wp3dafaMQ?autoplay=1><img src=https://img.youtube.com/vi/Y8Wp3dafaMQ/hqdefault.jpg alt='Video The Dark Knight Rises: What Went Wrong? – Wisecrack Edition'><span>▶</span></a>"   frameborder="0"   allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"   allowfullscreen   title="The Dark Knight Rises: What Went Wrong? – Wisecrack Edition" ></iframe>
Comparison of a YouTube embed and an iframe with just an image in side. Barely different at all, visually.

Custom Post Types everywhere

I’m a big fan of giving myself structured data to work with. In WordPress-land, that often means Custom Post Types paired with something like the Advanced Custom Fields plugin for just the right data needed for the job.

Three CMS input screens: Add New Conference (with conference related fields), Add New Interview, and Add New Action Item.

Then I can loop over stuff and output it however I want. This isn’t that fancy, but it opens up whatever future doors I want to a lot easier.

Build your own bio

There is nothing fancy about how this works:

Bio generator showing HTML for my personal bio. Radio buttons next to it to change 1st to 3rd person, length, and code type of bio.

I literally made 18 <div> elements (3 lengths * 2 styles * 3 code types = 18) and swap between with a bit of JavaScript that calculates a class string based on the current choices, selects that class, and unhides it while hiding the rest.

$ (".bio-choices input").on("change", function () {   var lengthClass = ".bio-" + $ ("input[name=length]:checked").attr("id");   var styleClass = ".bio-" + $ ("input[name=style]:checked").attr("id");   var codeClass = ".bio-" + $ ("input[name=code]:checked").attr("id");   var selector = lengthClass + styleClass + codeClass;    $ (".bio").hide();   $ (selector).show(); });

jQuery! That’s what was already on the site, and the site also uses the jQuery version of FitVids for responsive videos — so I figured I’d just leave it all be.

If I was going to re-write these bits of the site, I’d probably rip out jQuery and use this for FitVids. Then I’d find a way to only have three bios (maybe six if I can’t find a nice way to handle first vs. third person with word swaps) and then get the rest by automatically converting the formats somehow (maybe some cloud function if I had to).

ztext.js

I used ztext for the header! It’s this kinda stuff that makes the web feel extra webby to me. I’m not sure I’d do something with quite so much movement on a site like CSS-Tricks (because people visit it more often and the time-on-site is higher). But for a site that people might land on once in a blue moon, it has the right amount of cheerful levity, I think.

Background SVG

I was stoked to see the SVG Backgrounds site get an upgrade lately. I was playing around in there and was like YES, I’m doing this.

SVG backgrounds website showing off wavy dark gray lines over black, configurable through a controls panel.

I went with a background-attachment: fixed look, which I think I like. I also added the slideout footer effect on desktop, but I’m less sold that it’s working here. It’s more fun when the background changes, and that doesn’t happen here. I’ll probably either change the background of the footer, or rip the effect out.

Filter trick for links

Some of the different sections on the site use a different primary highlight color, and I’m having the links in those sections follow that color. That might be questionable (perhaps all links should be blue) but, so far, I think it makes decent sense (they still have hover and focus styles). When you have a variety of colors and styles for interactive elements though, it often means that you have to create special alternate styles for hover and focus. That could mean crafting bespoke color alterations for each color. Not the end of the world, but I really like this little trick for interactive styles that ends up with a consistent look across all colors:

a:focus, .button:focus, a:hover, .button:hover {   filter: brightness(120%); }

Anyway! This was just a couple hours of paint on this site. Mostly because blogrolls were the CodePen Challenge that week. But I can never touch a site I haven’t in a while and just do one thing. I get sucked in and gotta do more!


The post Little Things on My Personal Site appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , ,
[Top]

A little bit of plain Javascript can do a lot

Julia Evans:

I decided to implement almost all of the UI by just adding & removing CSS classes, and using CSS transitions if I want to animate a transition.

An awful lot of the JavaScript on sites (that aren’t otherwise entirely constructed from JavaScript) is click the thing, toggle the class — which is why jQuery was so good and libraries like Alpine.js are finding happy developer audiences.

I once did a screencast called “Hey designers, if you only know one thing about JavaScript, this is what I would recommend which was basically: learn to toggle classes. From that:

Sometimes, to start a journey into learning something huge and complex, you need to learn something small and simple. JavaScript is huge and complex, but you can baby step into it by learning small and simple things. If you’re a web designer, I think there is one thing in particular that you can learn that is extremely empowering.

This is the thing I want you to learn: When you click on some element, change a class on some element.

Direct Link to ArticlePermalink

The post A little bit of plain Javascript can do a lot appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]

Cool Little CSS Grid Tricks for Your Blog

I discovered CSS about a decade ago while trying to modify the look of a blog I had created. Pretty soon, I was able to code cool things with more mathematical and, therefore, easier-to-understand features like transforms. However, other areas of CSS, such as layout, have remained a constant source of pain.

This post is about a problem I encountered about a decade ago and, until recently, did not know how to solve in a smart way. Specifically, it’s about how I found a solution to a long-running problem using a modern CSS grid technique that, in the process, gave me even cooler results than I originally imagined.

That this is not a tutorial on how to best use CSS grid, but more of a walk through my own learning process.

The problem

One of the first things I used to dump on that blog were random photos from the city, so I had this idea about having a grid of thumbnails with a fixed size. For a nicer look, I wanted this grid to be middle-aligned with respect to the paragraphs above and below it, but, at the same time, I wanted the thumbnails on the last row to be left-aligned with respect to the grid. Meanwhile, the width of the post (and the width of the grid within it) would depend on the viewport.

The HTML looks something like this:

<section class='post__content'>   <p><!-- some text --></p>   <div class='grid--thumbs'>     <a href='full-size-image.jpg'>       <img src='thumb-image.jpg' alt='image description'/>     </a>     <!-- more such thumbnails -->   </div>   <p><!-- some more text --></p> </section>

It may seem simple, but it turned out to be one of the most difficult CSS problems I’ve ever encountered.

Less than ideal solutions

These are things I have tried or seen suggested over the years, but that never really got me anywhere.

Floating impossibility

Floats turned out to be a dead end because I couldn’t figure out how to make the grid be middle aligned this way.

.grid--thumbs { overflow: hidden; }  .grid--thumbs a { float: left; }

The demo below shows the float attempt. Resize the embed to see how they behave at different viewport widths.

inline-block madness

At first, this seemed like a better idea:

.grid--thumbs { text-align: center }  .grid--thumbs a { display: inline-block }

Except it turned out it wasn’t:

The last row isn’t left aligned in this case.

At a certain point, thanks to an accidental CSS auto-complete on CodePen, I found out about a property called text-align-last, which determines how the last line of a block is aligned.

Unfortunately, setting text-align-last: left on the grid wasn’t the solution I was looking for either:

At this point, I actually considered dropping the idea of a middle aligned grid. Could a combo of text-align: justified and text-align-last: left on the grid produce a better result?

Well, turns out it doesn’t. That is, unless there’s only a thumbnail on the last row and the gaps between the columns aren’t too big. Resize the embed below to see what I mean.

This is pretty where I was at two years ago, after nine years of trying and failing to come up with a solution to this problem.

Messy flexbox hacks

A flexbox solution that seemed like it would work at first was to add an ::after pseudo-element on the grid and set flex: 1 on both the thumbnails and this pseudo-element:

.grid--thumbs {   display: flex;   flex-wrap: wrap; 	   a, &::after { flex: 1; } 	   img { margin: auto; } 	   &:after { content: 'AFTER'; } }

The demo below shows how this method works. I’ve given the thumbnails and the ::after pseudo-element purple outlines to make it easier to see what is going on.

This is not quite what I wanted because the grid of thumbnails is not middle-aligned. Thats said, it doesn’t look too bad… as long as the last row has exactly one item less image than the others. As soon as that changes, however, the layout breaks if it’s missing more items or none.

Screenshot collage. Shows how the layout breaks when the last row is not missing exactly one item to be full.
Why the ::after hack is not reliable.

That was one hacky idea. Another is to use a pseudo-element again, but add as many empty divs after the thumbnails as there are columns that we’re expecting to have. That number is something we should be able to approximate since the size of the thumbnails is fixed. We probably want to set a maximum width for the post since text that stretches across the width of a full screen can visually exhausting for eyes to read.

The first empty elements will take up the full width of the row that’s not completely filled with thumbnails, while the rest will spill into other rows. But since their height is zero, it won’t matter visually.

This kind of does the trick but, again, it’s hacky and still doesn’t produce the exact result I want since it sometimes ends up with big and kind of ugly-looking gaps between the columns.

A grid solution?

The grid layout has always sounded like the answer, given its name. The problem was that all examples I had seen by then were using a predefined number of columns and that doesn’t work for this particular pattern where the number of columns is determined by the viewport width.

Last year, while coding a collection of one element, pure CSS background patterns, I had the idea of generating a bunch of media queries that would modify a CSS variable, --n, corresponding to the number of columns used to set grid-template-columns.

$ w: 13em; $ h: 19em; $ f: $ h/$ w; $ n: 7; $ g: 1em;  --h: #{$ f*$ w}; display: grid; grid-template-columns: repeat(var(--n, #{$ n}), var(--w, #{$ w})); grid-gap: $ g; place-content: center; 	 @for $ i from 1 to $ n {   @media (max-width: ($ n - $ i + 1)*$ w + ($ n - $ i + 2)*$ g) {     --n: #{$ n - $ i}   } }

I was actually super proud of this idea at the time, even though I cringe looking back on it now. One media query for every number of columns possible is not exactly ideal, not to mention it doesn’t work so well when the grid width doesn’t equal the viewport width, but is still somewhat flexible and also depends on the width of its siblings.

A magic solution

I finally came across a better solution while working with CSS grid and failing to understand why the repeat() function wasn’t working in a particular situation. It was so frustrating and prompted me to go to MDN, where I happened to notice the auto-fit keyword and, while I didn’t understand the explanation, I had a hunch that it could help with this other problem, so I dropped everything else I was doing and gave it a try.

Here’s what I got:

.grid--thumbs {   display: grid;   justify-content: center;   grid-gap: .25em;   grid-template-columns: repeat(auto-fit, 8em); }

I also discovered the minmax() function, which can be used in place of fixed sizes on grid items. I still haven’t been able to understand exactly how minmax() works — and the more I play with it, the less I understand it — but what it looks like it does in this situation is create the grid then stretch its columns equally until they fill all of the available space:

grid-template-columns: repeat(auto-fit, minmax(8em, 1fr));

Another cool thing we can do here is prevent the image from overflowing when it’s wider than the grid element. We can do this by replacing the minimum 8em with min(8em, 100%) That essentially ensures that images will never exceed 100%, but never below 8em. Thanks to Chris for this suggestion!

Note that the min() function doesn’t work in pre-Chromium Edge!

Keep in mind that this only produces a nice result if all of the images have the same aspect ratio — like the square images I’ve used here. For my blog, this was not an issue since all photos were taken with my Sony Ericsson W800i phone, and they all had the same aspect ratio. But if we were to drop images with different aspect ratios, the grid wouldn’t look as good anymore:

We can, of course, set the image height to a fixed value, but that distorts the images… unless we set object-fit to cover, which solves our problem!

Another idea would be to turn the first thumbnail into a sort of banner that spans all grid columns. The one problem is that we don’t know the number of columns because that depends on the viewport. But, there is a solution — we can set grid-column-end to -1!

.grid--thumbs {   /* same styles as before */ 	   a:first-child {     grid-column: 1/ -1; 		     img { height: 13em }   } }

The first image gets a bigger height than all the others.

Of course, if we wanted the image to span all columns except the last, one we’d set it to -2 and so on… negative column indices are a thing!

auto-fill is another grid property keyword I noticed on MDN. The explanations for both are long walls of text without visuals, so I didn’t find them particularly useful. Even worse, replacing auto-fit with auto-fill in any of the grid demos above produces absolutely no difference. How they really work and how they differ still remains a mystery, even after checking out articles or toying with examples.

However, trying out different things and seeing what happens in various scenarios at one point led me to the conclusion that, if we’re using a minmax() column width and not a fixed one (like 8em), then it’s probably better to use auto-fill instead of auto-fit because, the result looks better if we happen to only have a few images, as illustrated by the interactive demo below:

I think what I personally like best is the initial idea of a thumbnail grid that’s middle-aligned and has a mostly fixed column width (but still uses min(100%, 15em) instead of just 15em though). At the end of the day, it’s a matter of personal preference and what can be seen in the demo below just happens to look better to me:

I’m using auto-fit in this demo because it produces the same result as auto-fill and is one character shorter. However, what I didn’t understand when making this is that both keywords produce the same result because there are more items in the gallery than we need to fill a row.

But once that changes, auto-fit and auto-fill produce different results, as illustrated below. You can change the justify-content value and the number of items placed on the grid:

I’m not really sure which is the better choice. I guess this also depends on personal preference. Coupled with justify-content: center, auto-fill seems to be the more logical option, but, at the same time, auto-fit produces a better-looking result.

The post Cool Little CSS Grid Tricks for Your Blog appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Some Little Improvements to My VS Code Workflow (Workspaces, Icons, Tasks)

I did a little thing the other day that I didn’t know was possible until then. I had a project folder open in VS Code like I always do, and I added another different root folder to the window. I always assumed when you had a project open, it was one top level root folder and that’s it, if you needed another folder elsewhere open, you would open that in another window. But nope!

We kind of have a “duo repo” thing going on at CodePen (one is the main Ruby on Rails app, and one is our microservices), and now I can open them both together:

Multiple folders open at once. This means I don’t need to deal with my symlinks anymore.

Now I can search across both projects and basically just pretend like it’s one big project.

When you do that for the first time and then close the VS Code window, it will ask you if you want to save a “Workspace.” Meh, maybe later, I always thought. I knew what it meant, but I was too lazy to deal with it. It’ll make a file, I thought, and I don’t really have a place for files like that. (I’d avoid the repo itself, just because I don’t want to force my system on anyone else.)

Well, I finally got over it and did it. I chucked all my .code-workspace files into a local folder. They are actually quite useful as files, because I can put the files in my Dock and one-click open my Workspace just how I like it.

Custom Workspace icons

Workspace files have special little icons like this:

The icon is a little generic, but I like it. A document with a little tiny VS Code icon below it.

Since I’m putting these in my Dock, I saw that as a cool opportunity to make them into custom icons! That’ll make it super clear for me and a little more delightful to use since I’ll probably reach for them many times a day.

Taking a little inspiration from the original, I snagged the SVG logo and plopped it on the bottom-right of my project logos.

Changing logos on macOS is as simple as “Get Info” on the file, clicking the logo in that panel, then pasting the image.

Now I can keep them in my Dock and open everything with a single click:

Launch terminal commands when opening a project

Now that I have these really handy one-click icons for opening my projects, I thought, “How cool would it be if it kicked off the commands to start the project too!” Apparently, that’s what Tasks are for, and it wasn’t too hard to set up (thanks, Andrew!). Right next to that settings file, at .vscode/tasks.json, is where I have this:

{   "version": "2.0.0",   "tasks": [     {       "label": "Run Gulp",       "type": "shell",       "command": "gulp",       "task": "default",       "presentation": {         "focus": false,         "panel": "shared",         "showReuseMessage": true,         "clear": true       },       "runOptions": {         "runOn": "folderOpen"       }     }   ] } 

That kicks off the command gulp for me whenever I open this Workspace. I guess you have to run the task once manually (Terminal → Run Task) so that it has the right permissions, then it works from there on out.

Overrides

I don’t think this is specific to Workspaces necessarily, but I really like how you can have a file like .vscode/settings.json in a project folder to override VS Code settings for a particular project.

For example, here on CSS-Tricks, I have a super basic Sass setup where Gulp preprocesses .scss into .css. That’s all fine, but it’s likely that I’ll search for a selector at some point. I don’t need to see it in .css because I’m not working in vanilla CSS. Like ever. I can put this in that settings file, and know that it’s just for this project, rather than all my projects:

{   "search.exclude": {     "**/*.css": true,   } }

The post Some Little Improvements to My VS Code Workflow (Workspaces, Icons, Tasks) appeared first on CSS-Tricks.

CSS-Tricks

, , , , , , ,
[Top]

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

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:

A palette of multiple hues might look something like this:

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:

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:

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:

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:

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 = e.target.getAttribute('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     section.style.display = '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.

CSS-Tricks

, , , , , ,
[Top]

Make Yourself a Little API With Netlify Functions

Here’s an example of a nice little use case for cloud functions. Glitch has this great package of friendly words. Say you wanted to randomly generate “happy-elephant” or “walking-tree”, and you need to do that on your website in JavaScript. Well, this package is pretty big (~200 KB), necessarily so, because it has big dictionaries of words in it. You wouldn’t want to ship that to your client-side JavaScript when you don’t have to.

Cloud functions are cool, and we can use them to give ourselves a little API for this package instead. That way the size doesn’t matter that much, it’s up on a server. Netlify makes this about as easy as it can be.

Here’s a repo that makes it all possible. It’s barely any code!

A functions folder with a Node file in it.

At the root of our project: /functions/random.js

This file will require the friendly-words package and export a single function. Essentially it grabs two random words, plops them together, and returns it.

const friendlyWords = require("friendly-words");  exports.handler = function(event, context, callback) {   const { predicates, objects } = friendlyWords;   const numberOfPredicates = predicates.length;   const numbersOfObjects = objects.length;    const randomPredicate =     predicates[Math.floor(Math.random() * numberOfPredicates)];   const randomObject = objects[Math.floor(Math.random() * numbersOfObjects)];    const output = `$ {randomPredicate}-$ {randomObject}`;    callback(null, {     headers: {       "Access-Control-Allow-Origin": "*"     },     statusCode: 200,     body: output   }); };

Deploy it to Netlify

We can configure Netlify to tell it we have this function in a netlify.toml file (just so we don’t even have to bother with the UI).

[build]   command = "#"   functions = "functions/"

But if I wanted to just tell Netlify this in Settings, I can:

Once it’s deployed, I gave it a nice site name, and then that cloud function will be available at a URL. You can even see it in the browser:

https://friendly-words.netlify.com/.netlify/functions/random

Now I don’t have to ship that package in my client-side JavaScript — I can just hit this URL to get what I want.

CORS

If I was hitting this URL from my own website also at friendly-words.netlify.com I wouldn’t have to worry about CORS, but if I need to use it from any other website, I do. Notice the Access-Control-Allow-Origin stuff in the Node JavaScript above. That takes care of that.

Demo

To use our little API, we can fetch from it. That’s it!


Does this pique your interest? Netlify has a ton of examples of using functions.


While I was doing this I came across Paul Kinlan’s article that does pretty much exactly the same thing, but his has some extra functionality as part of the API you might wanna check out.

The post Make Yourself a Little API With Netlify Functions appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

Having a Little Fun With Custom Focus Styles

Every front-end developer has dealt or will deal with this scenario: your boss, client or designer thinks the outline applied by browsers on focused elements does not match the UI, and asks you to remove it. Or you might even be looking to remove it yourself.

So you do a little research and find out that this is strongly discouraged, because the focus outline is there for a reason: it provides visual feedback for keyboard navigation (using the Tab key), letting users who can’t use a mouse or have a visual impairment know where they are on the screen.

This button shows a focus state with Chrome’s default outline style.

That doesn’t mean you’re stuck with this outline, though. Instead of removing it, you can simply replace it with something else. That way, you’ll keep your interface accessible and get more flexibility on how it looks, so you can better match your UI.

You can start by removing the default browser outline by selecting the focused state of the element and applying outline: none. Then, you may choose from each of the options ahead to replace it:

Change the background color

This works best for elements that can be filled, such as buttons. Select the focused state of the element and apply a contrasting background color to it. The higher the contrast the better because subtle changes may not be strong enough visual cues, particularly in cases where with color blindness and low-vision.

In the example below, both background and border color change; you may pick either or both.

Click or focus with the Tab key to view how this state looks.

See the Pen
Elements replacing native outline focus with background color
by Lari (@larimaza)
on CodePen.

Change the text color

If the element has any text, you can select the focused state and change its color. This also works for icons applied with mask-image; you can select the icon as a descendant of the focused element and change its background color, like the example button below.

See the Pen
Elements replacing native outline focus with text and icon color
by Lari (@larimaza)
on CodePen.

Again, contrast is key. You may also consider using an underline on text links and making it part of the changed state because, as the Web Content Accessibility Guidelines state:

Color is not used as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element. (Level A)
Understanding Success Criterion 1.4.1

Apply a box shadow

The box-shadow property can do exactly the same job as the outline, except it’s much more powerful — you can now control its color, opacity, offset, blur radius and spread radius. And if a border-radius is specified, the box shadow follows the same rounded corners.

See the Pen
Elements replacing native outline focus with box shadow
by Lari (@larimaza)
on CodePen.

You can get really creative with this technique (seriously though, don’t do this):

See the Pen
Elements replacing native outline focus with insane box shadow
by Lari (@larimaza)
on CodePen.

This works for virtually any type of focusable element, like toggles, checkboxes, radio buttons and slides.

See the Pen
Toggle and radio button replacing native outline focus with box shadow
by Lari (@larimaza)
on CodePen.

Increase the element’s size

As an alternative to color change, you may also resort to subtle size modification as focus feedback. In this example, we’re using transform: scale.

See the Pen
Elements replacing native outline focus with transform scale
by Lari (@larimaza)
on CodePen.

The key here is subtlety. Extreme size changes may cause content reflow, not to mention a poor experience for those who prefer reduced motion.

Replicate existing hover styles

If the element already has a contrasting hover style, you can simply take that style and apply it for the focused state as well. This is a rather elegant solution, as you don’t have to add any new colors or outlines to the interface.

Here’s an example where both the focus and hover states adopt a high contrast to the background of an element’s default style:

See the Pen
Elements replacing native outline focus with hover styles
by Lari (@larimaza)
on CodePen.

Bonus: Customize the default outline

Everything we’ve looked at so far takes the assumption that we want to remove the focus outline altogether. We don’t have to! In fact, it’s a border that we can customize.

button:focus {   outline: 3px dashed orange; }

That’s shorthand and could have been written this way if we want to fine-tune the styles:

button:focus {   outline-width: 3px;   outline-style: dashed;   outline-color: orange; }

One additional superpower we have is the outline-offset property, which is separate from the outline shorthand property but can be used alongside it to change the position of the focus ring:

button:focus {   outline: 3px dashed orange;   outline-offset: 10px; }

Conclusion

You can mix and match all of these options to get custom styles that look appropriate for each component type within your interface.

And it’s worth repeating: Don’t forget to use stark color contrasts and other visual cues in addition to color when adopting custom focus states. Sure, we all want an experience that aligns with our designs, but we can adhere to good accessibility practices in the process. The W3C recommends this tool to test the contrast of colors values against the WCAG guidelines.

The post Having a Little Fun With Custom Focus Styles appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]