Archiwum kategorii: CSS

Popping Comments With CSS Anchor Positioning and View-Driven Animations

Post pobrano z: Popping Comments With CSS Anchor Positioning and View-Driven Animations

The State of CSS 2024 survey wrapped up and the results are interesting, as always. Even though each section is worth analyzing, we are usually most hyped about the section on the most used CSS features. And if you are interested in writing about web development (maybe start writing with us 😉), you will specifically want to check out the feature’s Reading List section. It holds the features that survey respondents wish to read about after completing the survey and is usually composed of up-and-coming features with low community awareness.

Reading List Results, showing Anchor Positioning and View Driven Animations at the top 5

One of the features I was excited to see was my 2024 top pick: CSS Anchor Positioning, ranking in the survey’s Top 4. Just below, you can find Scroll-Driven Animations, another amazing feature that gained broad browser support this year. Both are elegant and offer good DX, but combining them opens up new possibilities that clearly fall into what most of us would have considered JavaScript territory just last year.

I want to show one of those possibilities while learning more about both features. Specifically, we will make the following blog post in which footnotes pop up as comments on the sides of each text.

CodePen Embed Fallback

For this demo, our requirements will be:

  • Pop the footnotes up when they get into the screen.
  • Attach them to their corresponding texts.
  • The footnotes are on the sides of the screen, so we need a mobile fallback.

The Foundation

To start, we will use the following everyday example of a blog post layout: title, cover image, and body of text:

CodePen Embed Fallback

The only thing to notice about the markup is that now and then we have a paragraph with a footnote at the end:

<main class="post">

  <!-- etc. -->

  <p class="note">
    Super intereseting information!
    <span class="footnote"> A footnote about it </span>
  </p>
</main>

Positioning the Footnotes

In that demo, the footnotes are located inside the body of the post just after the text we want to note. However, we want them to be attached as floating bubbles on the side of the text. In the past, we would probably need a mix of absolute and relative positioning along with finding the correct inset properties for each footnote.

However, we can now use anchor positioning for the job, a feature that allows us to position absolute elements relative to other elements — rather than just relative to the containment context it is in. We will be talking about “anchors” and “targets” for a while, so a little terminology as we get going:

  • Anchor: This is the element used as a reference for positioning other elements, hence the anchor name.
  • Target: This is an absolutely-positioned element placed relative to one or more anchors. The target is the name we will use from now on, but you will often find it as just an “absolutely positioned element” in other resources.

I won’t get into each detail, but if you want to learn more about it I highly recommend our Anchor Positioning Guide for complete information and examples.

The Anchor and Target

It’s easy to know that each .footnote is a target element. Picking our anchor, however, requires more nuance. While it may look like each .note element should be an anchor element, it’s better to choose the whole .post as the anchor. Let me explain if we set the .footnote position to absolute:

.footnote {
  position: absolute;
}

You will notice that the .footnote elements on the post are removed from the normal document flow and they hover visually above their .note elements. This is great news! Since they are already aligned on the vertical axis, we just have to move them on the horizontal axis onto the sides using the post as an anchor.

Example of the footnotes inside the posts and where do we want them

This is when we would need to find the correct inset property to place them on the sides. While this is doable, it’s a painful choice since:

  1. You would have to rely on a magic number.
  2. It depends on the viewport.
  3. It depends on the footnote’s content since it changes its width.

Elements aren’t anchors by default, so to register the post as an anchor, we have to use the anchor-name property and give it a dashed-ident (a custom name starting with two dashes) as a name.

.post {
  anchor-name: --post;
}

In this case, our target element would be the .footnote. To use a target element, we can keep the absolute positioning and select an anchor element using the position-anchor property, which takes the anchor’s dashed ident. This will make .post the default anchor for the target in the following step.

.footnote {
  position: absolute;
  position-anchor: --post;
}

Moving the Target Around

Instead of choosing an arbitrary inset value for the .footnote‘s left or right properties, we can use the anchor() function. It returns a <length> value with the position of one side of the anchor, allowing us to always set the target’s inset properties correctly. So, we can connect the left side of the target to the right side of the anchor and vice versa:

.footnote {
  position: absolute;
  position-anchor: --post;

  /* To place them on the right */
  left: anchor(right);

  /* or to place them on the left*/
  right: anchor(left);

  /* Just one of them at a time! */
}

However, you will notice that it’s stuck to the side of the post with no space in between. Luckily, the margin property works just as you are hoping it does with target elements and gives a little space between the footnote target and the post anchor. We can also add a little more styles to make things prettier:

.footnote {
  /* ... */

  background-color: #fff;
  border-radius: 20px;
  margin: 0px 20px;
  padding: 20px;
}

Lastly, all our .footnote elements are on the same side of the post, if we want to arrange them one on each side, we can use the nth-of-type() selector to select the even and odd notes and set them on opposite sides.

.note:nth-of-type(odd) .footnote {
  left: anchor(right);
}

.note:nth-of-type(even) .footnote {
  right: anchor(left);
}

We use nth-of-type() instead of nth-child since we just want to iterate over .note elements and not all the siblings.

Just remember to remove the last inset declaration from .footnote, and tada! We have our footnotes on each side. You will notice I also added a little triangle on each footnote, but that’s beyond the scope of this post:

CodePen Embed Fallback

The View-Driven Animation

Let’s get into making the pop-up animation. I find it the easiest part since both view and scroll-driven animation are built to be as intuitive as possible. We will start by registering an animation using an everyday @keyframes. What we want is for our footnotes to start being invisible and slowly become bigger and visible:

@keyframes pop-up {
  from {
    opacity: 0;
    transform: scale(0.5);
  }

  to {
    opacity: 1;
  }
}

That’s our animation, now we just have to add it to each .footnote:

.footnote {
  /* ... */
  animation: pop-up linear;
}

This by itself won’t do anything. We usually would have set an animation-duration for it to start. However, view-driven animations don’t run through a set time, rather the animation progression will depend on where the element is on the screen. To do so, we set the animation-timeline to view().

.footnote {
  /* ... */
  animation: pop-up linear;
  animation-timeline: view();
}

This makes the animation finish just as the element is leaving the screen. What we want is for it to finish somewhere more readable. The last touch is setting the animation-range to cover 0% cover 40%. This translates to, “I want the element to start its animation when it’s 0% in the view and end when it’s at 40% in the view.”

.footnote {
  /* ... */
  animation: pop-up linear;
  animation-timeline: view();
  animation-range: cover 0% cover 40%;
}

This amazing tool by Bramus focused on scroll and view-driven animation better shows how the animation-range property works.

What About Mobile?

You may have noticed that this approach to footnotes doesn’t work on smaller screens since there is no space at the sides of the post. The fix is easy. What we want is for the footnotes to display as normal notes on small screens and as comments on larger screens, we can do that by making our comments only available when the screen is bigger than a certain threshold, which is about 1000px. If it isn’t, then the notes are displayed on the body of the post as any other note you may find on the web.

.footnote {
  display: flex;
  gap: 10px;

  border-radius: 20px;
  padding: 20px;

  background-color: #fce6c2;

  &::before {
    content: "Note:";
    font-weight: 600;
  }
}

@media (width > 1000px) {
  /* Styles */
}

Now our comments should be displayed on the sides only when there is enough space for them:

CodePen Embed Fallback

Wrapping Up

If you also like writing about something you are passionate about, you will often find yourself going into random tangents or wanting to add a comment in each paragraph for extra context. At least, that’s my case, so having a way to dynamically show comments is a great addition. Especially when we achieved using only CSS — in a way that we couldn’t just a year ago!


Popping Comments With CSS Anchor Positioning and View-Driven Animations originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

2024: More CSS At-Rules Than the Past Decade Combined

Post pobrano z: 2024: More CSS At-Rules Than the Past Decade Combined

More times than I can count, while writing, I get myself into random but interesting topics with little relation to the original post. In the end, I have to make the simple but painful choice of deleting or archiving hours of research and writing because I know most people click on a post with a certain expectation of what they’ll get, and I know it isn’t me bombing them with unrelated rants about CSS.

This happened to me while working on Monday’s article about at-rules. All I did there was focus on a number of recipes to test browser support for CSS at-rules. In the process, I began to realize, geez we have so many new at-rules — I wonder how many of them are from this year alone. That’s the rabbit hole I found myself in once I wrapped up the article I was working on.

And guess what, my hunch was right: 2024 has brought more at-rules than an entire decade of CSS.

It all started when I asked myself why we got a selector() wrapper function for the @supports at-rule but are still waiting for an at-rule() version. I can’t pinpoint the exact reasoning there, but I’m certain there wasn’t much of a need to check the support of at-rules because, well, there weren’t that many of them — it’s just recently that we got a windfall of at-rules.

Some historical context

So, right around 1998 when the CSS 2 recommendation was released, @import and @page were the only at-rules that made it into the CSS spec. That’s pretty much how things remained until the CSS 2.1 recommendation in 2011 introduced @media. Of course, there were other at-rules like — @font-face, @namespace and @keyframes to name a few — that had already debuted in their own respective modules. By this time, CSS dropped semantic versioning, and the specification didn’t give a true picture of the whole, but rather individual modules organized by feature.

Random tangent: The last accepted consensus says we are at “CSS 3”, but that was a decade ago and some even say we should start getting into CSS 5. Wherever we are is beside the point, although it’s certainly a topic of discussion happening. Is it even useful to have a named version?

The @supports at-rule was released in 2011 in CSS Conditional Rules Module Level 3 — Levels 1 and 2 don’t formally exist but refer to the original CSS 1 and 2 recommendations. We didn’t actually get support for it in most browsers until 2015, and at that time, the existing at-rules already had widespread support. The @supports was only geared towards new properties and values, designed to test browser support for CSS features before attempting to apply styles.

The numbers

As of today, we have a grand total of 18 at-rules in CSS that are supported by at least one major browser. If we look at the year each at-rule was initially defined in a CSSWG Working Draft, we can see they all have been published at a fairly consistent rate:

Number of at-rules per year in FWPD. They all have been added at an average rate of 1 per year, with the highest being 4 in 2021

If we check the number of at-rules supported on each browser per year, however, we can see the massive difference in browser activity:

Number of at-rules per year in FWPD visualized by the browsers that implemented them in a colorful vertical bar chart.

If we just focus on the last year a major browser shipped each at-rule, we will notice that 2024 has brought us a whopping seven at-rules to date!

Numbers of at-rules with support in at least one major browsers. There have been seven that gained support in 2024
Data collected from caniuse.

I like little thought experiments like this. Something you’re researching leads to researching about the same topic; out of scope, but tangentially related. It may not be the sort of thing you bookmark and reference daily, but it is good cocktail chatter. If nothing else, it’s affirming the feeling that CSS is moving fast, like really fast in a way we haven’t seen since CSS 3 first landed.

It also adds context for the CSS features we have — and don’t have. There was no at-rule() function initially because there weren’t many at-rules to begin with. Now that we’ve exploded with more new at-rules than the past decade combined, it may be no coincidence that just last week the Chrome Team updated the function’s status from New to Assigned!

One last note: the reason I’m even thinking about at-rules at all is that we’ve updated the CSS Almanac, expanding it to include more CSS features including at-rules. I’m trying to fill it up and you can always help by becoming a guest writer.


2024: More CSS At-Rules Than the Past Decade Combined originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Smashing Hour With Heydon Pickering

Post pobrano z: Smashing Hour With Heydon Pickering

I sat down with Heydon Pickering in the most recent episode of the Smashing Hour. Full transparency: I was nervous as heck. I’ve admired Heydon’s work for years, and even though we run in similar circles, this was our first time meeting. You know how you build some things up in your mind and sorta psyche yourself out? Yeah, that.

Heydon is nothing short of a gentleman and, I’ll be darned, easy to talk to. As is the case with any Smashing Hour, there’s no script, no agenda, no nothing. We find ourselves getting into the weeds of accessibility testing and documentation — or the lack of it — before sliding into the stuff he’s really interested in and excited about today: styling sound. Dude pulled out a demo and walked me (and everyone else) through the basics of the Web Audio API and how he’s using it to visualize sounds in tons of groovy ways that I now want hooked up to my turntable somehow.


Smashing Hour With Heydon Pickering originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Recipes for Detecting Support for CSS At-Rules

Post pobrano z: Recipes for Detecting Support for CSS At-Rules

The @supports at-rule has been extended several times since its initial release. Once only capable of checking support for property/value pairs, it can now check for a selector using the selector() wrapper function and different font formats and techs using font-format() and font-tech(), respectively. However, one feature the community still longs for is testing other at-rules support.

@supports at-rule(@new-rule) {
  /* @new-rule is supported */
}

The CSSWG decided in 2022 to add the prior at-rule() wrapper function. While this is welcome and wonderful news, here we are two years later and we don’t have a lot of updates on when it will be added to browsers. So, how can we check for support in the meantime?

Funny coincidence: Just yesterday the Chrome team changed the status from “new” to “assigned” as if they knew I was thinking about it.

Looking for an answer, I found this post by Bramus that offers a workaround: while we can’t check for a CSS at-rule in the @supports at-rule, we can test a property that was shipped with a particular at-rule as a substitute, the thinking being that if a related feature was released that we can test and it is supported, then the feature that we’re unable to test is likely to be supported as well… and vice versa. Bramus provides an example that checks support for the animation-timeline property to check if the @scroll-timeline at-rule (which has been discontinued) is supported since the two were shipped together.

@supports (animation-timeline: works) {
  /* @scroll-timeline is supported*/
}

/* Note: @scroll-timeline doesn't exist anymore */

Bramus calls these “telltale” properties, which is a fun way to think about this because it resembles a puzzle of deduction, where we have to find a related property to check if its at-rule is supported.

I wanted to see how many of these puzzles I could solve, and in the process, know which at-rules we can reliably test today. So, I’ve identified a full list of supportable at-rules that I could find.

I’ve excluded at-rules that offer no browser support, like @color-profile, @when, and @else, as well as deprecated at-rules, like @document. Similarly, I’m excluding older at-rules that have enjoyed wide browser support for years — like @page, @import, @media, @font-face, @namespace and @keyframes — since those are more obvious.

@container size queries (baseline support)

Testing support for size queries is fairly trivial since the module introduces several telltale properties, notably container-type, container-name and container. Choose your favorite because they should all evaluate the same. And if that property is supported, then @container should be supported, too, since it was introduced at the same time.

@supports (container-type: size) {
  /* Size queries are supported! */
}

You can combine both of them by nesting a @supports query inside a @container and vice versa.

@supports (container-type: size) {
  @container (width > 800px) {
    /* Styles */
  }
}

@container style queries (partial support)

Size queries give us a lot of telltale properties to work with, but the same can’t be said about style queries. Since each element has a style containment by default, there isn’t a property or value specific to them. We can work around that by forgetting about @supports and writing the styles inside a style query instead. Style queries work in supporting browsers but otherwise are ignored, so we’re able to write some base styles for older browsers that will be overridden by modern ones.

.container {
  --supports-style-queries: true;
}

.container .child {
  /* Base styles */
}

@container style(--supports-style-queries: true) {
  /* Container queries are supported! */
  .child {
    /* We can override the base styles here */
  }
}

@counter-style (partial support)

The @counter-style at-rule allows us to make custom counters for lists. The styles are defined inside a @counter-style with custom name.

@counter-style triangle {
  system: cyclic;
  symbols: ‣;
  suffix: " ";
}

ul {
  list-style: triangle;
}

We don’t have a telltale property to help us solve this puzzle, but rather a telltale value. The list-style-type property used to accept a few predefined keyword values, but now supports additional values since @counter-style was introduced. That means we should be able to check if the browser supports <custom-ident> values for list-style-type.

@supports (list-style: custom-ident) {
  /* @counter-style is supported! */
}

@font-feature-values (baseline support)

Some fonts include alternate glyphs in the font file that can be customized using the @font-feature-values at-rule. These custom glyphs can be displayed using the font-variant-alternatesl, so that’s our telltale property for checking support on this one:

@supports (font-variant-alternates: swash(custom-ident)) {
  /* @font-feature-values is supported! */
}

@font-palette-values (baseline support)

The same concept can be applied to the @font-palette-values at-rule, which allows us to modify multicolor fonts using the font-palette property that we can use as its telltale property.

@supports (font-palette: normal) {
  /* @font-palette-values is supported! */
}

@position-try (partial support)

The @position-try at-rule is used to create custom anchor fallback positions in anchor positioning. It’s probably the one at-rule in this list that needs more support since it is such a new feature. Fortunately, there are many telltale properties in the same module that we can reach for. Be careful, though, because some properties have been renamed since they were initially introduced. I recommend testing support for @position-try using anchor-name or position-try as telltale properties.

@supports (position-try: flip-block) {
  /* @position-try is supported! */
}

@scope (partial support)

The @scope at-rule seems tricky to test at first, but it turns out can apply the same strategy we did with style queries. Create a base style for browsers that don’t support @scope and then override those styles inside a @scope block that will only be valid in supporting browsers. A progressive enhancement strategy if there ever was one!

.foo .element {
  /* Base style */
}

@scope (.foo) to (.bar) {
  :scope .element {
    /* @scope is supported, override base style */
  }
}

@view-transition (partial support)

The last at-rule in this list is @view-transition. It’s another feature making quick strides into browser implementations, but it’s still a little ways out from being considered baseline support.

The easiest way would be to use its related view-transition-name property since they released close together:

@supports (view-transition-name: custom-ident) {
  /* @view-transition is supported! */
}

But we may as well use the selector() function to check for one of its many pseudo-elements support:

@supports selector(::view-transition-group(transition-name)) {
  /* @view-transition is supported! */
}

A little resource

I put this list into a demo that uses @supports to style different at-rules based on the test recipes we covered:

CodePen Embed Fallback

The unsolved ones

Even though I feel like I put a solid list together, there are three at-rules that I couldn’t figure out how to test: @layer, @property, and @starting-style.

Thankfully, each one is pretty decently supported in modern browsers. But that doesn’t mean we shouldn’t test for support. My hunch is that we can text @layer support similar to the approaches for testing support for style() queries with @container where we set a base style and use progressive enhancement where there’s support.

The other two? I have no idea. But please do let me know how you’re checking support for @property and @starting-style — or how you’re checking support for any other feature differently than what I have here. This is a tricky puzzle!


Recipes for Detecting Support for CSS At-Rules originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

WPGraphQL Becomes a Canonical Plugin: My Move to Automattic

Post pobrano z: WPGraphQL Becomes a Canonical Plugin: My Move to Automattic

It’s always a gas when a good person doing good work gets a good deal. In this case, Jason’s viral WPGraphQL plugin has not only become a canonical WordPress plugin, but creator Jason Bahl is joining Automattic as well.

I’m linking this up because it’s notable for a few reasons:

Congrats, Jason! I didn’t know you were in Denver — maybe we’ll bump into each other and I can give you a well-deserved high-five. ✋


WPGraphQL Becomes a Canonical Plugin: My Move to Automattic originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

CSSWG Minutes Telecon (2024-08-14)

Post pobrano z: CSSWG Minutes Telecon (2024-08-14)

I was just going over the latest CSSWG minutes (you can subscribe to them at W3C.org) and came across a few interesting nuggets I wanted to jot down for another time. The group discussed the CSS Values, CSS Easing, and Selectors modules, but what really caught my eye was adding triggered delays to CSS for things like hover, long taps, and focus states.

The idea stems from an OpenUI proposal, the same group we can thank for raising things like the Popover API and customizable select element. The concept, if I understand it right, is that anytime someone hovers, taps, or focuses on, say, a <button> for a certain amount of time, we can invoke some sort of thing. A tooltip is the perfect illustration. Hovering over the trigger element, the reasoning goes, is an expression of interest and as web authors, we can do something with that interest, like displaying a tooltip.

A mouse cursor hovering an info button with an hourglass next to it indicating time passed before showing a tooltip.

Whoa, right?! There’s long been chatter about CSS encroaching on JavaScript territory (isn’t it ironic, don’t you think?). Firing events in response to interaction is quite literally the only thing I use JavaScript for. There’s no mistake about that in the CSSWG, as documented in the minutes:

So. Does this belong in CSS? Or should it be elsewhere? Does the approach make sense? Are there better ideas? Most interested in the last.

[…]

Other question; does this belong in CSS or HTML… maybe this is just a javascript feature? In JS you can determine MQ state and change things so it wouldn’t necessarily be in CSS.

And shortly later:

As you were talking; one thing that I kept thinking of; should developers be customizing the delay at all? Original use case for delay is that hover shouldn’t be instant. But if we don’t allow for customizing we can align to platform delay lengths.

But there’s an excellent point to be made about the way many of us are already doing this with CSS animations (animation-delay) and transitions (transition-delay). Sometimes even applying those globally with the Universal Selector or a prefers-* query.

Things get even hairier when considering how values are defined for this. Are they explicit delays (800ms), generic keywords (none/short/medium/long), a custom property, a pseudo-class… something else? I’m glad there’re incredibly smart folks noodling on this stuff.

I think here it would be good to go with time values. CSS is a good place to put it. We have all the ergonomics. The right declarative place to put it.

Whatever the eventual case may be:

I think this sounds reasonable and I’d like to explore it. Unsure if this is the exact shape, but this space seems useful to me.


CSSWG Minutes Telecon (2024-08-14) originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

How are the `colspan` and `rowspan` attributes different?

Post pobrano z: How are the `colspan` and `rowspan` attributes different?

Yes, yes. Functionally, they are different. But heck if I didn’t know about the wacky thresholds until Jens Oliver Meiert tooted a pair of quick polls.

According to the HTML Standard:

  1. If the current cell has a colspan attribute, then parse that attribute’s value, and let colspan be the result.
    If parsing that value failed, or returned zero, or if the attribute is absent, then let colspan be 1, instead.
    If colspan is greater than 1000, let it be 1000 instead.
  2. If the current cell has a rowspan attribute, then parse that attribute’s value, and let rowspan be the result.
    If parsing that value failed or if the attribute is absent, then let rowspan be 1, instead.
    If rowspan is greater than 65534, let it be 65534 instead.

I saw the answers in advance and know I’d have flubbed rowspan. Apparently, 1000 table columns are plenty of columns to span at once, while 65534 is the magic number for clamping how many rows we can span at a time. Why is the sweet spot for rowspan 6,4543 spans greater than colspan? There are usually good reasons for these things.

What that reason is, darned if I know, but now I have a little nugget for cocktail chatter in my back pocket.


How are the `colspan` and `rowspan` attributes different? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

On the Ground at Frostapalooza

Post pobrano z: On the Ground at Frostapalooza

I can’t say I would have ever expected to see Jeremy Keith performing the Yeah Yeah Yeahs song “Maps”, but then again, I don’t know what I expected to happen at Frostapalooza.

The Event

Brad Frost, web designer, author of Atomic Design, and an absolute maniac on the bass, celebrated his birthday by putting together a one-night-only benefit concert featuring musical performances by himself and his talented family and friends.

Frostapalooza, held at Mr. Smalls Theatre in Pittsburgh, PA, was an all-ages event where 100% of the proceeds are headed towards two great causes:

  • NextStep Pittsburgh: Helping provide accessible rehabilitation for folks with spinal cord injuries and paralysis in Pittsburgh.
  • Project Healthy Minds: Providing research and resources to help tackle mental health.

Performances

The variation of musical performances sprawled across the night, covering tracks by Fleetwood Mac, Radiohead, David Bowie and so much more, check out this setlist of all 31 tracks on Spotify.

I loved the performance of Pink Floyd’s classic song, “Money.” As a Floyd fan who will never get to see them live, this was easily the best rendition I could ask for, which included the full lineup of instrumental sections.

Brad was joined on stage by none other than CSS-Tricks founder, Chris Coyier. Chris picked banjo on a few songs, such as Johnny Cash’s “Folsom Prison Blues” and The Band’s “The Weight,” both fantastic.

The stage background prominently displayed visuals out of CodePen demos made by CodePen community members during the set. Check out the Frostapalooza tag on CodePen to see everything that was projected.

Another favorite moment was Brad’s version of “Wake Up” by Arcade Fire, which felt like a perfectly matched song for the evening.

Musicians

If you haven’t caught on yet, many of the folks lending their musical talents to Frostapalooza also happen to be web designers and developers Brad has met and worked with during his career. At times it felt like the Wu-Tang Clan of CSS on stage.

Brad’s family and musicians from his other bands pitched in, such as Elby Brass. Ridiculously impressive! I had never seen a tuba-playing lead vocalist until this night.

You can see the full lineup on the event’s website. But I’ll drop a screenshot in here just for posterity.

Full lineup of musicians who performed at Frostapalooza.

Photos! Videos!

Mike Aparicio captured a great video of a group jam on Queen’s “Bohemian Rhapsody” that you’ve got to watch on YouTube. Brian Kardell nabbed this gem of Chris pickin’ on “The Weight”:

Party boy Brad Frost shared a bunch of other photos from the event in a Google Photos album.

The end

Plain and simple, this was a super fun night celebrating music and friends. Happy birthday, Brad, and thanks for putting on an awesome show!


On the Ground at Frostapalooza originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

All About JavaScript Loops

Post pobrano z: All About JavaScript Loops

Every programming language has loops. Loops perform an operation (i.e., a chunk of work) a number of times, usually once for every item in an array or list, or to simply repeat an operation until a certain condition is met.

JavaScript in particular has quite a few different types of loops. I haven’t even used all of them, so for my own curiosity, I thought I’d do a high-level overview of them. And as it turns out, there are pretty good reasons I haven’t used at least a couple of the different types.

So, for now let’s spend a while exploring the different types of loops, what we can do with each of one, and why you might use one over another. (You’ll think that little play on words is absolutely hilarious by the end.)

The while and do...while loops

First up is the while loop. It’s the most basic type of loop and has the potential to be the easiest to read and the fastest in many cases. It’s usually used for doing something until a certain condition is met. It’s also the easiest way to make an infinite loop or a loop that never stops. There is also the do...while statement. Really, the only difference is that the condition is checked at the end versus the beginning of each iteration.

// remove the first item from an array and log it until the array is empty
let queue1 = ["a", "b", "c"];

while (queue1.length) {
  let item = queue1.shift();

  console.log(item);
}

// same as above but also log when the array is empty
let queue2 = [];

do {
  let item = queue2.shift() ?? "empty";

  console.log(item);
} while (queue2.length);

The for loop

Next is the for loop. It should be the go to way to do something a certain number of times. If you need to repeat an operation, say, 10 times, then use a for loop instead. This particular loop may be intimidating to those new to programming, but rewriting the same loop in the while-style loop can help illustrate the syntax make it easier to stick in your mind.

// log the numbers 1 to 5
for (let i = 1; i <= 5; i++) {
  console.log(i);
}

// same thing but as a while loop
let i = 1; // the first part of a for loop

// the second
while (i <= 5) {
  console.log(i);

  i++; // the third
}

("end");

The for...of and for await...of loops

A for...of loop is the easiest way to loop through an array.

let myList = ["a", "b", "c"];

for (let item of myList) {
  console.log(item);
}

They aren’t limited to arrays though. Technically they can iterate through anything that implements what is called an iterable protocol. There are a few built-in types that implement the protocol: arrays, maps, set, and string, to mention the most common ones, but you can implement the protocol in your own code. What you’d do is add a [Symbol.iterator] method to any object and that method should return an iterator. It’s a bit confusing, but the gist is that iterables are things with a special method that returns iterators; a factory method for iterators if you will. A special type of function called a generator is a function that returns both a iterable and iterator.

let myList = {
  *[Symbol.iterator]() {
    yield "a";
    yield "b";
    yield "c";
  },
};

for (let item of myList) {
  console.log(item);
}

There is the async version of all the things I just mentioned: async iterables, async iterators, and async generators. You’d use an async iterable with for await...of.

async function delay(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

// this time we're not making an iterable, but a generator
async function* aNumberAMinute() {
  let i = 0;

  while (true) {
    // an infinite loop
    yield i++;

    // pause a minute
    await delay(60_000);
  }
}

// it's a generator, so we need to call it ourselves
for await (let i of aNumberAMinute()) {
  console.log(i);

  // stop after one hour
  if (i >= 59) {
    break;
  }
}

One unobvious thing about for await...of statement is that you can use it with non-async iterables and it will work just fine. The reverse, however, is not true; you can’t use async iterables with the for...of statement.

The forEach and map loops

While these are not technically loops per se, you can use them to iterate over a list.

Here is the thing about the forEach method. Historically it was much slower than using a for loop. I think in some cases that may not be true anymore, but if performance is a concern, then I would avoid using it. And now that we have for...of I’m not sure there is much reason to use it. I guess the only reason that it still may come up is if you have a function ready to use as the callback, but you could easily just call that same function from inside the body of for...of.

forEach also receives the index for each item though, so that may be a thing you need too. Ultimately, the decision to use it will probably come down to whether any other code you’re working with uses it, but I personally would avoid using it if I’m writing something new.

let myList = ["a", "b", "c"];

for (let item of myList) {
	console.log(item);
}

// but maybe if I need the index use forEach
["a", "b", "c"].forEach((item, index) => {
  console.log(`${index}: ${item}`);
});

Meanwhile, map essentially converts one array into another. It still has the same performance impact that forEach has, but it is a bit nicer to read than the alternative. It’s certainly subjective though, and just like with forEach you’ll want to do what the rest of your other code is doing. You see it a ton in React and React-inspired libraries as the primary way to loop through an array and output a list of items within JSX.

function MyList({items}) {
  return (
    <ul>
      {items.map((item) => {
        return <li>{item}</li>;
      })}
    </ul>
  );
}

The for...in loop

This list of loops in JavaScript wouldn’t be complete without mentioning the for...in statement because it can loop through the fields of an object. It visits fields that are inherited through the object’s prototype chain too, though, and I’ve honestly always avoided it for that reason.

That said, if you have an object literal, then for...in might be a viable way to iterate through the keys of that object. Also it’s worth noting that if you’ve been programming JavaScript for a long time, you may remember that the order of keys use to be inconsistent between browsers, but now the order is consistent. Any key that could be an array index (i.e., positive integers) will be first in ascending order, and then everything else in the order as authored.

let myObject = {
  a: 1,
  b: 2,
  c: 3,
};

for (let k in myObject) {
  console.log(myObject[k]);
}

Wrapping up

Loops are something that many programmers use every day, though we may take them for granted and not think about them too much.

But when you step back and look at all of the ways we have to loop through things in JavaScript, it turns out there are several ways to do it. Not only that, but there are significant — if not nuanced — differences between them that can and will influence your approach to scripts.


All About JavaScript Loops originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.