428: This is 40, Code Health, Firefox Follow Up, Accessible Text Labels, and Minifying your Project

Download MP3

We're reflecting on turning 40, code health and integration testing, Mozilla Firefox conversations, the best way to provide an accessible text label to a button, and finding an application that minifies JavaScript and images files.



Chris Coyier and Dave Rupert in silly sunglasses and a sign that says Shawp Tawlkk Shough DOT COM

Chris Coyier and Dave Rupert

This episode is with just Chris & Dave, ShopTalk Show's hosts. Chris is the co-founder of CodePen and creator of CSS-Tricks, and Dave is lead developer at Paravel.

Time Jump Links

  • 01:14 This is 40
  • 04:00 Code health and integration testing
  • 17:52 Sponsorship: Imgix
  • 21:04 Mozilla Firefox follow up
  • 34:05 Sponsor: Framer
  • 35:13 What's the best way to provide an accessible text label to a button with an icon as a background image?
  • 44:13 Is there an application that minifies javscript and images files?


[Banjo music]

MANTRA: Just Build Websites!

Dave Rupert: Hey there, Shop-o-maniacs. You're listening to another episode of the ShopTalk Show. I'm Dave--just end of summer days--Rupert and with me is Chris--headed into fall--Coyier. How are you, Chris?

Chris Coyier: Does it feel like the end of summer in Austin?

Dave: Well, it's still 109,000, but it's [laughter] -- you know, and it will be for a while. We've got a few hurricanes headed this way, but you know. Hopefully, everyone is safe. Yeah, it'll cool off. Usually, the hurricanes will cool it off. Yep, that's where we're at.

Chris: That's good. Yeah, it's kind of cool today here, too. Yeah. Yeah, I don't know. I don't know. Sorry about the -- I'm not in the booth again because I just have been having back trouble, so I just want to be able to sit down and stand up and stuff, as I need to. It's just been a pain in the butt, but it's getting better. I just came from the physical therapist. It should be all right.

Dave: Oh, hey, I'm going to juice my mic a bit. Hey, do you feel like you're on a path to health or not quite yet?

Chris: I do. I do. I do, but there's so much to health. I'm thinking about this a lot because, as I speak, by the time somebody hears this on a podcast, I'll be 40. Today is the day before my 40th birthday.

Dave: Hey!

Chris: I turn 40 tomorrow.

Dave: Exciting!

Chris: Yeah, it's a decade coming on.

Dave: Happy birthday, Chris. You get it.

Chris: I'm not one of those types that's worried about my, like, yeah, I'm not depressed. I'm not going to buy a Corvette. I don't have any mental hang-ups about the year, but it does make you think a little bit. I'm like, oh, man. Last summer, I really got screwed because I broke both my fricken' arms and missed a lot of the funness of summer just being bummed out about that. Now I'm rolling up on another birthday and this back thing has been -- it's nothing like my arms. This is just a little back pain, but it feels similar and be like, I've fallen apart here.

Dave: Oh.

Chris: I just feel like I need to be taking my health a lot more seriously. I need to commit myself to it because I think your life is just better and always. Your physical self is so important, too. You think it's like, oh, it's a separate world than your mental health, but it's really not.

Dave: No.

Chris: You need to have good physical health to have good mental health. It's just a lot. I'm not in a dark place, but I really want to prevent myself from getting there at all. I think physical health is probably my biggest trigger at the moment.

Dave: I was definitely feeling that last year at this time. I was definitely in your boat. Then even the year before that, it was like my wrists and RSI was up.

Chris: Ugh!

Dave: It's just like, god!

Chris: Been there, too.

Dave: You know. That's why I led in with that pathway question because if you don't have that pathway to success or there's no clear answer, that's when it just sucks. You're like, I'm going to feel like this forever. This sucks. Anyway, I hope you're feeling better. Yeah, I wrote a bunch of--

Chris: I feel like I have the pathway.

Dave: I wrote a bunch of blog posts. It was a pretty emotional time, but it was just like, you know-- It gives me sympathy for people who are in chronic pain or something like that just because it's hard work, man. It just changes your whole, like, what you're able to do.

Chris: Yeah. You know what affects it, too, in here is a little bit of this, like, we're dads of young children.

Dave: Mm-hmm.

Chris: Mine are even younger than yours are.

Dave: Yeah.

Chris: I don't want to be -- I'm only 40. That's not that particularly old. I don't want to be the dad that's always, [grunting] "Oh, gawd. I can't get up." [Grunting]

Dave: Yeah. Cripes. Cripes. Yeah.

Chris: That's a sucky dad.

Dave: [Laughter] Cripes. Gawd, I can't.

Chris: I'm way too young for that garbage.

Dave: Mm-hmm.

Chris: I want to be hopping around doing awesome stuff, you know.

Dave: No. Yeah.

Chris: Gotta turn that around. That's cool. You all don't need to hear about my health, though. I just think it's kind of, you know, we talk about what's on our mind to some degree.

Code health is an interesting kind of health, too, if we were going to segue this into something interesting.

Dave: Mm-hmm. Okay.


Chris: I think of it because I've spent the last two whole days working on some integration tests. You know? You ever write an integration test, Dave? [Laughter]

Dave: I try not to. No, I don't have a good system. Are you using Cypress? I would assume, or something. No?

Chris: No. Well, not only because, on this particular project, we've tried Cypress before and I had reliability problems with it. Now, don't read that into Cypress is a bad product. I think it's actually best of breed out there for writing integration tests. It's really good, generally.

Dave: Yeah.

Chris: It's a little like jQuery, too. I think if you came from that world that you'll enjoy this, the syntax of it. You write this test that's select this, then do this, then expect this to happen, like, what's the test of this button?

I think I've written before that I'm kind of a big fan of wide light integration tests. If you run an integration test, it goes to this URL, it clicks this button, something happen, and the text is what you think it should be, that's amazing. That's a ton of stuff has gone right in your app. You should feel pretty safe about deploying it. I think that's kind of cool, you know. Run those. They don't have to be super detailed, long, or anything.

Dave: What are you doing for your integration tests then?

Chris: What we're doing?

Dave: What's your--?

Chris: Puppeteer.

Dave: Puppeteer?

Chris: Just raw.

Dave: Okay.

Chris: Then just Puppeteer on top of it. If you care about the minutia of it, there is a project called Just Puppeteer, just-puppeteer.

Dave: Uh-huh.

Chris: For some reason, we don't use that. [Laughter] You can use then on top of that expect-puppeteer, and they're all about sugar.

Dave: Yeah.

Chris: They're all just like, look at how little code you have to write if you use all these tools. You can write this three-line thing of code and then it does what it's supposed to do. You don't have to worry about the globals, the setup, and stuff. I think the more of those tools you strip away, the more to the metal kind of control you have. I think that's what was important for us when we were setting these up. I'm not doing this for the first time. I'm redoing them because of a move to GitHub actions.

Dave: Okay. Yeah.

Chris: Which are, I think, really cool. It's just different. You're doing all this work. You might as well revisit how it's all being done.

Dave: Yeah. It's just flavor integration tests, basically, that control Puppeteer.

Chris: Yeah, and you still run it with Jest. The command line you end up writing an NPM script that calls Jest, run in band, blah-blah-blah. We have some sugar on top of it, like we have special configs because I think the roots of Jest were unit tests.

Dave: Mm-hmm. Mm-hmm.

Chris: We use it for that, too, so we have 100-some-whatever unit tests testing some stuff, which is honestly, for unit tests, is a little light on stuff. But, hey, so be it. Because there are two kinds of Jest tests, we have two separate configs: one of them that goes and looks for all the unit tests and runs those and one that looks for the integration tests and runs those. It can kind of run it with different config. Then because we don't use as much of the sugar stuff, we can access kind of low-level Puppeteer stuff like we want to wait until the network is idle.

What we had trouble with Cypress was some reliability of tests. Sometimes they would just fail. The second you're in a situation where you run a test once and it passes, and you run a test again and it goes through, your trust is just gone.

Dave: Yeah. Yeah. Right.

Chris: No longer can you attach that to not being able to merge the branch, for example, because somebody is going to be annoyed by it and they're just going to turn it off because it's not reliable or something.

The goal--and this could be a fool's errand, so feel free to laugh at us--was 100% reliable integration tests or very close to it. If an integration test fails, you've really got to look at it. I think we got there by having low-level metal access to this thing.

Dave: Okay.

Chris: Being able to tweak things really low and writing fairly simple integration tests. Yeah, so anyway, it's been fun. It's been fun to--

Dave: Yeah, well, that's good to hear. Can you give me an example of a simple or a complex integration test? It's like, okay, crack my knuckles. I want to add tests. Then I'm just like, I don't know. [Laughter] What do I actually want to do here? What's a simple or a complex?


Chris: Well, login is an obvious one.

Dave: Yeah.

Chris: You go to this page and you type in some credentials. Now, that's another thing that we did, though, because almost everything we do is behind a login that we went so far as to modify the Puppeteer prototype. By the time we create a session at all, we pass it a parameter of what type of account you want to log in as. By the time you're even looking at the browser window, you're already logged in as a correct context of user. That's not really a test. It is a test because, if it doesn't work, it'll fail, but you know.

Dave: Mm-hmm.

Chris: There's that. But there's one just like, hey, it tries to visit our admin page. Now, you shouldn't; nobody should have access to that. If it visits that page as a logged in free user, it better as hell 404.

Dave: Right. Okay.

Chris: If it doesn't, that's a really bad problem. This test is really short. It goes to that URL. It expects to find the very vanilla 404 page. If it doesn't, that test fails.

Dave: Oh, that's easy. It's that easy.

Chris: It is that easy and that's a big one because it's so easy to write. That test will just then sit there forever.

Dave: Mm-hmm.

Chris: It'll run and it'll pass a thousand times before, one day, it doesn't pass and somebody goes, "Oh, crap!" [Laughter]

Dave: I broke the login.

Chris: We broke that. Yeah. It's more likely that you're going to break the test than you are going to be that functionality, but these are guards, and the more of them the better.

A more complicated one is it visits the pen editor on CodePen. It sets the preprocessor to Sass. It puts some Sass code into the thing. It then saves the pen. Then visits the saved URL. Then looks inside the pen preview and sees that the body is background red or something even though you wrote that in Sass with the variable. That's a little finicky, you know.

Dave: Okay.

Chris: There are things that go wrong, but that's probably as complex as I'd get. It's got to follow a URL somewhere. It's got to--

Dave: Wait for a network request and all that. Yeah.

Chris: Because, theoretically, what you don't want to do is then write ten more steps after that. It's like, well, the go-to full pageview and see if it looks right in full pageview. Then go to debug view and see. What you want to test is just does full pageview work? That should be a separate test.

Dave: Yeah. Okay.

Chris: Don't make it this chain of actions that's ten chained long because the reliability of that is going to be much worse for very little gain.

Dave: Mm-hmm. Mm-hmm. No, that sounds right. You're just trying to -- what's the shortest testable path, sort of. I need to see that it has--

Chris: Right.

Dave: --a background of red. Don't care. Just show me that.

Chris: Yeah, after you put the code in and ran it or whatever. Now, I am not the master of this, but I think there is a concept called an end-to-end test where the point of it is a longer chain of actions.

Dave: Mm-hmm. Mm-hmm.

Chris: I think that's the distinction between end-to-end.

Dave: With Cypress, you can do that, like hearts content. You can make that flow, that it clicks through, and fills out as long as you want it to. Right?

Chris: Right. Right, right. I like, with a lot of this, that every line of code you write is kind of a test.

Dave: Mm-hmm.

Chris: You're like, for example, in Cypress, and even with the way we're doing it too, it's kind of like wait for this element and then click it or wait for this element and check the text inside of it and then go to the next line. That previous line where you did that, that's a little tiny test.

Dave: Mm-hmm.

Chris: Did the button exist? If it doesn't exist, it's gone. The test isn't an assertation of, "Does button exist?" But it will fail if it doesn't find the button, so it's kind of like an implied test.

Dave: Yeah.

Chris: Kind of cool.


Dave: No, that's cool. I think that's like -- I just need to do it. Probably more accurately, I need to be in a situation where I'm forced to do it or money is on the line that it needs to be done.

Chris: Right. Right, right, right.

Dave: I've been in those situations and have written tests, but it's not creative testing. It's not like, "Ooh, how do I test this?" I don't end up in those situations.

Chris: In a sense, it's okay if it's reactionary, I think. For us, it's like this is a big app. We've had problems before. We've had these up in the past. They've saved us in the past. It's just worth doing and it's been on our list for a long time because sometimes they break and they get in weird states. It's just been on my mind to get these going.

Plus, with the move to GitHub Actions, for us, it's been a chance to reevaluate all kinds of DevOp stuff. I have done 2% of this compared to our team. I'm just kind of like hopping in with ideas and getting these little things because, ultimately, the GitHub Actions thing, it's not just doing this. This is one tiny little thing that it's doing.

Dave: Right. Yeah.

Chris: The other stuff that it's doing is, you know, it's getting a docker container already with all the prebuilt assets on it and deploying it to AWS and running all the Ruby tests and running all the -- I don't know. There's like 16 steps and then I'm hopping in and doing one after it's all done.

Dave: Yeah.

Chris: Then it runs the integration test at the end, so I did one tiny little piece of this thing.

Dave: You're like, I did it! [Laughter] Hey look, Alex. I did it.

Chris: I did it!

Dave: Aren't you proud? [Laughter]

Chris: Yeah. Yeah, Alex is like bleeding blood out of his forehead and I'm just like, "Hey, can you help me fix my integration?"

Dave: Look, the admin page. It's there. [Laughter]

Chris: Yeah. Yeah. But I like to think it's important, so I work on it. But I've also added a few other things in because there are good docs around this. I mean it's not like CI is some new concept.

Dave: Yeah.

Chris: It's just -- I don't know. The fact that it's on GitHub now breathes some life into this, at least for me. For example, Ben and Karolina. They run Calibre.

Dave: Mm-hmm.


Chris: They made an open-source image optimizer thing. One of the cool things about CI, in this case, is you can just write this thing to be like, just run whatever commands you want at the command line, essentially. Or you can be like, or just point it at this other repo. Use that one, the thing that already exists.

Dave: Mm-hmm.

Chris: It kind of like marketplace-izes CI to some degree. You can be like, oh, you know one step in my workflow? Just run their thing.

Dave: Right.

Chris: Their thing is, optimize all images in the repo, which is really neat. Another thing about this, just for context, is that you kind of set up the triggers of when you want these things to run. They can run whenever you push anything to any branch or they can run only when you push to certain branches. Or they can only run on PRs. Or they can run only when you click a button, for example.

Dave: Yeah.

Chris: There are a number of different triggers and you say what you want. Theirs only works on PRs on purpose. You make a PR. It just automatically looks at every file in your repo, finds images, optimizes them, and then auto-commits the changed images. Pretty cool.

Dave: Bingo-bango.

Chris: Then it tells you. It leaves a little comment on the PR that's like, "I found five. I optimized them. This is how much you saved." Cool. And it's a little commit.

Now, it's not cyclical because a commit can trigger another workflow.

Dave: Sure. Sure. Sure. Sure.

Chris: But that's why it only works on PRs is because then that commit doesn't trigger another workflow and it's safe.

Dave: Okay. Okay. Cool.

Chris: That's cool. You chuck that one in there. Now I can never ever commit an image to the repo that's not optimized. It's just solved forever. That's the appeal of this, which I think is just really cool.

Dave: I might need the deets on that. My big plan, I think we've maybe talked about this on the last show but converting over to 11ty.

Chris: Yeah.

Dave: For my site. Then part of that is to run Lighthouse CI and stuff like that just so I get to play with these build processes a bit more. Having a mixed Ruby Node environment wasn't fun to me, setting that up. I guess you all would have that, so I'm curious. I bet that wasn't fun. [Laughter] But if I was all just Node land, it would be a little bit easier for me.

Chris: Yeah.

Dave: So, I'm kind of curious how that would work. I want to play with that, and so part of my mental blocker is I should move all over to Node first and then I could play with these toys, but not, it's--

Chris: Kind of. Yeah, I mean I definitely find that highly appealing.

Dave: Yeah.

Chris: Sticking in JavaScript land is a good idea. There are all kinds of powerful stuff you can do with it. I'm feeling that more and more now that, for example, I mentioned cloud functions a lot. It's just like a little instance of Chrome in the sky.

Dave: [Laughter]

Chris: Just runs V8, you know? Then I've been playing with Electron, too, because of the side project app. You know what that is? It's a little Chrome.

Dave: A little Chrome app.

Chris: We use it. Chrome has just taken over. [Laughter] You know? When your life is just all this little JavaScript instances, it's just -- I don't know. I could see why people are -- it's appealing.


[Banjo music starts]

Chris: This episode of ShopTalk Show is brought to you in part by Imgix. That's It's a powerful image and processing API. I'm going to get into it and explain it. I think it's a fantastic product.

I asked them once how you pronounce it and I have it right, so this is podcast friendly. Imgix. Imgix. Like I said, fantastic product. Let me set the stage for you a little bit, though.

You know we talk about build processes sometimes on the show. You could, for example, make sure that your build process optimizes all your images. By the time that they're up on your Web server and they're being served to people, they're optimized.

That's one of the things you need to do. I don't think it's optional either. You have to be serving your images in an optimized format. Sure, okay, you can do that yourself, but I always feel like if I do it myself, it's limited compared to what a company who's absolutely focused on this job can do.

Then it's not just the optimizing it, but it's serving it in the correct format and being able to manipulate it in different situations. Let me talk about that a little bit more.

For example, how you set up Imgix is like this. You have a master location of where your images are. Maybe it's your Web server. It doesn't matter that much. I don't think you need to pre-CDN your images because what Imgix does is it sits in front of your master images as the global CDN, which is fantastic anyway because you need a global CDN for your images if you want your site to be fast and responsible. In fact, Lighthouse will ding you for it if it's not. If you're going for those good scores, that's important.

Maybe it's an S3 bucket. That's a common way. That's a way I've worked with Imgix before. That's your master location and then you have these URLs that are

Then what you have then is the ability to add query parameters that's like, I want it served in this size. I want it to be automatically compressed the best that you possibly can. Let's say I change the aspect ratio. I want you to crop it. I want you to crop it towards this focal point. I want you to blur it. I want you to make it black and white. I want you to combine it with this other image.

It has all these powerful possibilities well being served from a global CDN, so you wouldn't even need to put this stuff in your build process because you could just make the images that you upload in dev or while you blog or whatever be the master images that are just huge, unoptimized, just source images, which I think is kind of nice because then you're not ruining your source image. Then because you're serving them through Imgix, they're optimized in the best possible way. They're served in the best possible format.

We did challenges at CodePen where we did four weekly challenges that kind of dug into those things. For example, the picture element is one of them. You know how you want to serve responsive images and do fancy art direction kind of stuff? Then you could use Imgix and then all you have to do is change the query parameter of the master image to be like, "Well, I wanted it this size at this particular breakpoint and this size at this particular breakpoint." You can be fancy and just have one master image. You're not handmaking all these images.

It's the way to go. Thanks so much for this sponsorship, Imgix.

Chris Enns: Make sure you visit and sign up to receive a $300 account credit.

[Banjo music stops]


Dave: This is a good segue to correct. I think, in the last show, we had speculated. Oh, Mozilla is maybe switching to Chrome or that's the only move that makes sense. Then you kind of let a tweet out that felt like that.

Thankfully, some Mozillans actually showed up in the thread, like Marcos--I'm going to murder your last name--Caceres. Marcos Caceres was like, "We're not switching to Chrome. Please stop speculating."

That's like, cool. It's good to hear that, but it was also very not clear in the post. You know? There was no reissued commitment to Gecko.

Chris: Right. Is that the official word? He works there.

Dave: He works there.

Chris: So, is that it?

Dave: He's part of the remnant, we'll call them. [Laughter] I don't think--

In the official post, there was no official recommitment to Gecko and open-source. Well, maybe open-source, but there was no recommitment, so I think the speculation was fair. Then, like we said before, specifically, dev tools. Dude, they nuked the team, so what does that mean for a browser? I don't know what to do.

Chris: All we can do is wait because nothing makes sense. Nothing still makes sense. All we can do is see, like, okay, you're going to do something, so what is it going to be? Is the first thing going to be a blog post about how we shipped some new, important Web platform features? Boy, would I eat crow if that's what it was.

Dave: [Laughter]

Chris: I would, really. Somebody would need to be like, "Chris, you're a dumb idiot. You should close your blog because, wow."

Then why did you fire a bunch of Web platform people? You know? I don't know.

Dave: Yeah. No, I don't understand. The direction is not clear to me as a Web developer and as a businessperson. I would say that. [Laughter]

Chris: Both of those things, right?

Dave: From those identities that I possess, it is not clear.

Chris: Is there a pride thing too? Is another possible story, the actual framing of it is, "We have failed as a business, like our stab," because startups fail all the time, right?

Dave: Mm-hmm.

Chris: It's a little less intense. You're like, "Well, we had an idea and we went for it. We even took some money, but it didn't work, so we failed. We're very sorry, but we have to shut down now." They're not talking about shutting down, but they're doing the next thing, which is like, "Well, we're we tried but we couldn't do it."

There's none of that. This is a little COVID blamey and stuff like that. But is that their actual story? They tried some things? I'm not sure what those things were, but they didn't work.

Dave: In the post, they have a few links. They're buried as those one-word links where you kind of just chuck inferences in a link.

Chris: Sure. I do that.

Dave: It's my favorite style. It's maybe kind of bad for accessibility, if I were totally being transparent. That's my favorite style of link is when somebody just links one word and it goes off to this whole other fricken' universe of links. Anyway -- [laughter] they had some posts and it was a bunch of different projects.

One mission they are building were the ones, but they're kind of like one project is a communication platform that's free for prisoners because people in the U.S., they get charged $2 billion. It's a $2 billion industry for prisoners to talk to their family or whatever. And so, they're trying to disrupt that, which I think is kind of cool.

Chris: Yeah.

Dave: I think I'm going to build the free version of something that exists doesn't necessarily get them to their economic goals, but there were a bunch of -- I'm not slandering it, but this is how it appeared to me was intern projects or 20% time projects that were kind of like, "Oh, look. We have this idea about a way to do something in kind of an incubator style series of apps or features and stuff like that." I think that's cool and I think that should be part of Mozilla, but it was no super clear on the browser side of things.

Maybe Mozilla ceases to be a browser. That's kind of different world thinking.

Chris: Yeah, maybe.

Dave: Maybe they have a browser but they cease to be that or something. I don't know. I don't know.

Chris: I also wanted to -- when I said, "Hey, maybe they'll--" it seems to me they either stagnate or they go Chromium. That was the two things I put out. Maybe that's a little reductive, so if there's a third option, let's see it. At the moment, I don't quite feel the need to walk my words back on that one. It seems like that's kind of -- I'd like to see what the option is. Prove me wrong kind of thing.

Dave: Yeah. Yeah.


Chris: But I don't want to make it feel like going Chromium -- maybe this is controversial too, but I don't see that as being a disaster. I know a lot of people feel a lot more strongly about browser engine diversity, but it just seems to me like the ball has already been rolling this way and I don't think it's stoppable. I also think that if we get finally there and we lost Mozilla and it was down to just WebKit and Chromium that it's still not the end of the world. It doesn't spell some disaster for the Web. I just don't see it as being all that terrible.

Dave: Mm-hmm.

Chris: Whatever.

Dave: Yeah.

Chris: That's just me. But I know a lot of people are real stoked about that. All the less cross-browser testing that you have to do. That's the reductive view of it.

There used to be this one that I would point to as one that I thought was weird that Google would do. There was this -- you know about local storage, right? It's key value. You throw something in a local storage. You pull it back out. But it's not asynchronous. If you're going to use it, it has to be sync.

Dave: Yeah.

Chris: Google comes out with this other idea. They're like, we're going to have a KV store that's not like that. It's just a little more flexible. We think it's a better-engineered thing. The way that you use it is that you import like an ES6 import, a file, but it's built into the browser, so it's this concept called native modules. You can just import this file like you're doing it from NPM but you don't have to NPM install anything. It's just sitting there waiting for you to use.

I'm like, "Wow. That's weird," but cool. I get it. I'm not opposed to it, but I don't know. Where did it come from? Has this been vetted? Is this talked about? Whatever.

Then it kind of just shipped. I don't know the status of it as we speak right now, but it seems like that's kind of the new normal is that sometimes these ideas just come along and that's the way they are. They just exist now.

There's another one I just saw about local fonts. Did you happen to see that one, web.devblog?

Dave: No. No.

Chris: It's a new API for asking for a list of your local fonts. Something like Figma might do that to make available your local fonts in their Web software, so you can use them, which I think is an obviously tremendously good use case. You can already do that. If you install the Figma app locally, it just does that. If you use Figma on the Web, you use a browser extension, and then it does that. This would mean that you wouldn't need the browser extension. It would just do it. Fine, right? But it turns out it's an obvious loophole for fingerprinting.

Dave: Right. Security problem.

Chris: You know. Sure, and everybody said that in all the reviews of this thing. They talk about it heavily in the post. They say, "Here's the thing. You could identify a Google employee because all Google machines have this special corporate font that they load."

Dave: [Laughter]

Chris: Right there, you could tell if it's a Google employee or not.

Dave: Yikes. Yikes, okay.

Chris: But they talk about it and I think the idea is that it's going to be like the geolocation. You've got to approve it. You know?

Dave: Okay.

Chris: I think that satisfies everybody, right? People don't complain about geolocation, right? You've got to ask, so the asking is the permission. If you don't want to enable it then don't.

They say, "Listen. We're not just shipping this. We're in the gather feedback stage. We're going to iterate upon the idea." Shipping it doesn't come until much later, so they're to head this off at the path but I think the vibe is still very much like, "Yeah, but we're doing it." You know?

Dave: Mm-hmm.

Chris: Like, "Get used to it. Here's the thing. We're going to go through all the right steps but it's a thing that we're shipping." I think that's kind of like the new normal.

Dave: Mm-hmm.

Chris: Especially if you lose Firefox too, which might happen. I don't know. Everybody is saying -- people are saying the exact opposite; Firefox is sticking around. But you lose them too, that really becomes the new normal. It'll just be like, you find out what's happening on the Web by reading

Dave: Right. Then there goes to WebKit and then there's a lot of WebKit. Then everyone will hate WebKit because it doesn't have the fonts. You know? Sort of cascades--I don't know--a blame game. You know?

I've seen people really upset about Mozilla and Apple putting their feet down on features. But then you talk to people at Mozilla and Apple and they're like, "Oh, yeah. That's really bad." [Laughter] You're like, "Oh, gees. Okay."

Chris: That's the new war, isn't it? It's Apple saying -- It's Google saying, "We need this new thing because the Web needs to be competitive as a platform." It's been stopped right and left by reasons.

Dave: Mm-hmm.

Chris: Then other companies saying, like, "Yeah, but those reasons are important.

Dave: Right and, you know, I don't know which multibillion-dollar company to trust anymore, Chris. I'm just at a loss.

Chris: Oh, my god. Nice.

Dave: I don't know which billionaire--

Chris: Nice throwback to the Apple epic war you're referencing.

Dave: What's that?

Chris: [Laughter] I thought you were talking about making a reference to the Apple versus Epic thing.

Dave: Oh, yeah. No, that's--

Chris: Which -- yeah.

Dave: That's the same thing. I mean Apple was like, "Oh, we don't -- you have to use our payment." That sucks too if that's the Web. You know? The Web gets locked down by just a few vendors, that sucks too, you know. Silos and mono-browser cultures aren't good.

I think the majority of our industry is probably too young now, just as things have changed and whatever, to remember, like, "Oh, you can't go to that website because that was built for IE. You can't go to that on Firefox," or whatever. It was literally built with a specific set of technologies that only work on this thing, so you just can't go to it. People forget those days and those were not cool, fun days.

Chris: All right. Well, that was kind of fun. Sorry. I feel like I'm not -- more negative than I want to be about all this. Mostly, I'm just curious and want to know what's happening. The fact that I don't know anything is what's getting me there, I think.

Dave: That compounds the issue, too. I think there's a lot of confusing, there's a lot of, like, "Oh, they do this," or "That browser does that," or "They're not going to do this or that." You know like you and I; we are pundits in the Web development world. We follow this stuff. We read up on it. We click links. We read links. I half read links. You actually read the links.

We abide in this stuff, imbibe this stuff, and it's not clear to us who do a weekly podcast. That's weird to me. It would seem like somebody -- there needs to be some clear messaging, it would seem. That's what gets me.


[Banjo music starts]

Chris: This episode of ShopTalk Show is brought to you by Framer. That's Go there. Sign up for free or get 20% off any paid plan. That's very generous. Thank you, Framer.

When you've spent hours designing something beautiful for the Web, the last thing you want to hear is, "Uh, sorry. Uh, we can't build this." You know? Ew. Ew.

What you need is a tool that bridges the gap between design and development. Framer can be that bridge. It's a browser-based prototyping tool that enables designers to use code-backed components and dynamic transitions to visually express ideas. When the time comes that you perhaps, as the designer, are giving it to a developer, the developer can jump in and easily inspect the elements, get the CSS or the JSX right from there. Custom animations, custom-built with Magic Motion.

It's powered by Framer Motion, which is an open-source library that's awesome that you should check out for React. It all comes with complete, clean code, which can be taken right from Framer and you can move it right into production. It's the gap. Framer is the bridge.

Sign up for free or get 20% off any paid plan by visiting That's

[Banjo music stops]


Chris: I really like this question that we got in from Steven Garrity.

Steven Garrity: Hello, ShopTalk Show. Steven Garrity here from Prince Edward Island, Canada. [Bird call with music] I was recently asked a question by a colleague and it seemed like a very basic CSS question. "What's the best way to provide an accessible text label to a button with an icon?" The icon was a background image in this case.

I've been designing and developing for the Web for, like, 20 years. I could probably rhyme off five or ten different ways to achieve this. You could make the icon a background. Make the background image into a real IMG tag with Alt text or use one of a slew of CSS-Tricks to visually hide the text and put an ARIA label on the button. But it occurred to me that I just couldn't give this person a straight answer on the best approach in the most common cases.

My question is, what is the best way to provide an accessible text label for an icon on the Web in 2020? I could code up all the alternative approaches I can think of and test them in every browser and device and screen reader and other assistive tech tools. Surely, we've settled on a convention as an industry for this by now. I'm afraid that the answer is going to be, "It depends." Thanks.

Dave: This is a good question because there's also input-type=image, too, that you could use. [Laughter] Anyway, don't do that one.

Chris: I would think that the answer is, it's a span that's visually hidden so that it's a real Web element. Under what circumstances does that not work? It seems like that should be kind of the go-to, I would think.

Dave: Yeah. Possibly. I think if you have an SVG in there, does it have a label? The hidden span is pretty good. More often than not, in the accessibility work I've done, that's been the recommendation. Just have SR only is what Bootstrap calls it, or visually hidden is what a lot of the old Yahoo blog posts, YUI posts had.

Having text in there is sort of like, okay, this is the best way to provide text but hide text. Yeah, I think a button, you could do an SVG and then the SR-only text. I think that works great. You want to make sure the SVG doesn't get read or anything weird.

Chris: I'd rather just do the SR only on a span that's sitting next to the SVG than try to fiddle with the internals of the SVG to make sure it has something in there that ends up being read. That's probably possible but it just seems like you're fighting against a more uncertain world if you do that rather than just use the span that you've kicked off the page that you absolutely know is going to work that's going to work with translation.

Dave: Yeah. No, I mean that's the thing too. ARIA label doesn't work with translation. ARIA label is great, but it's a clobber. It's a clobbering tool. Browsers may make that work eventually but, yeah, the span should get translated by, like, Google Translate or Chrome Translate or whatever. I think that's a great, probably baseline.

Chris: I just can't think offhand of a situation where a span kicked off the page is bad. I think there is one, but I can't remember what it is. Maybe it has to do with focus or something.

Dave: If you do margin-left 99999 pixels or whatever, you're asking a lot of the browser. You're like, "Hey, browser. By the way, one layer of this site is this big. Good luck. Keep that in your brain." You know?

Chris: Yeah.

Dave: I think it affects rendering speed and stuff like that.

Chris: If you can do overflow hidden, you don't have to do that. You can just do it negative 100%. Then it's just barely kicked off.

Dave: Yeah. Yeah, I mean I always do the clip 111 or whatever.

Chris: Hmm. There you go.

Dave: Zero pixel clip or whatever that's absolutely positioned or whatever.

Chris: Sure.

Dave: I like that. Very few drawbacks to that. I don't know. I do wish we had an invisible text or something attribute or something. I guess I could just make it, but I think that would help. I don't know. This is something we do all the time is provide assistive text via this. It would be cool to have whatever.

Chris: It does, doesn't it? There are three obvious ways to hide something with CSS. There's display none and we know not to use that for accessibility if it needs to be because, when you display none, it's just wiped off. It's wiped off.

Dave: It disappears from the tree.

Chris: Every plate, including accessibility's access to it.

Dave: Mm-hmm.

Chris: Opacity zero does not do that but it's also just sitting there on the page then.

Dave: It takes up space.

Chris: It's still taking up space, which you may not want to. Then there's visibility hidden, and I think visibility hidden has its uses too, but also has the accessibility one. You know?

Dave: Mm-hmm. Yeah. I don't know the full impact of that one, but it's not there. It's not it either. Yeah, not good.

Chris: No, but what we don't have is some kind of HTML native, you know, do it this way for the specific situation of it needs to be visually hidden but accessibly available.

Dave: Yeah, and we have the opposites. We have hidden, the hidden attribute, which is like display none, basically. Like, don't pay attention to this at all.

Inert is like, "This isn't technically hidden. This is like an off-screen menu or something. Don't hide this but just don't pay attention to it. I'm going to use it later," is sort of how Inert works. You know? I'm going to animate this in and remove the attribute, or something.

Yeah, we don't have just for reading, this is readable only or something. I don't know. Read-only. We have a read-only attribute, but no. What is the--?

Chris: I'm sure this has been talked about. Don't you think? It seems like such a big thing.

Dave: I would think so. I would think so.

Chris: …issues with it. Yeah.

Dave: I saw some Adam Argyle demos that had an invisible attribute on there and I was like, "Whoa, whoa, whoa. What's this?" He just had made up some attribute to style off of, basically like--

Chris: Yeah, I think Adam is pretty chill about the, just make up attributes, thing.

Dave: [Laughter] Hey.

Chris: I don't know. I'm less chill than Adam is about it, I think. I really actively try to avoid it these days, just because I think it's just a really simple choice. You put data dash in front of it or not and I think if everyone put data dash in front of it when it's not one that exists on the Web platform then it just makes it a little safer. I think you read enough stuff by people like Mike Taylor. He's like, "Well, one website did this thing and now nobody can have nice things because, if we ever change it, it breaks Trello," or something.

Dave: Yeah. No, I mean that's it. Well, everybody. We tried to do this but MooTools did it. Womp-womp-womp. Yeah, not necessarily -- sorry, Adam. This isn't like the Adam show or anything, but--

Chris: [Laughter]

Dave: There is a place where he knows what he's doing but somebody might just come along and copy/paste and just go with it and roll it out in a thing. That's where it becomes a problem, so anyway.

Chris: Yeah, I've had that happen to me a lot because I'm called out for that if something is wrong on CSS-Tricks. I don't get the luxury of just saying, "It's just a demo for a dumb little blog post," you know? Because it's usually pointed out in the same sentence that you don't get that caveat.

Dave: Mm-hmm.

Chris: People copy and paste from this site. That's the point of this site. You don't get that one. It has to be right.

Dave: Yeah. Yeah.

Chris: Which I think is fair.

Dave: Hopefully, Steven, that answers your question. Just use a screen reader only, visually hidden span and that's probably the best way to do it. This is very common. Close button. Download cloud button. Share, subscribe buttons right now. Handclap button on Medium. You know, everything. This is a very common pattern. Search buttons. Good luck. I wish it was a simpler thing, like simple answers.


Chris: Um, we're got a question here from Dylan Lynch asking about minification. Dylan says, "Is there an application that minifies all of your HTML, CSS, and JavaScript and image files in one go and gives you back a folder, the same folder but just all minified? Then you can use that to upload it to your server. I thought there would be a program like this but I couldn't find anything."

Dave: Uh--

Chris: That's an interesting question, Dylan. A couple things come to mind. Something like CodeKit might be. I don't know that it will do exactly that, but it could be configured to pretty quickly. I think that's the gist of it is less thinking. Please process my files kind of app.

Dave: Mm-hmm.

Chris: But that's Mac only, so that's not going to help you a ton there. I also think of things like, well, if Cloudflare is in front of your site, then it just kind of does all those things without you needing to manually do them. Maybe that is appealing.

Dave: Parcel might get you pretty close.

Chris: Oh, yeah. There you go.

Dave: You can just pass files into it. You'll have to -- I make this mistake all the time. You need the source directory and then everything compiles to the build, or dist., or _site director, however you're doing it. I do this wrong all the time. I just start building in one folder, but you gain a lot of favors for yourself if you have a source folder, SRC inside of whatever you're working on. I would recommend that.

Chris: I spent my morning, actually, with Webpack, in addition to some of the other things I was doing. Oh, my gosh. I know Webpack gets easy to dunk on, and I'm not trying to do because I think it's just been -- the fact that it's as big as it is, there's something to be said for what it's done for the world. You know? Probably a net gain overall, though that might be a controversial opinion. I don't know. But it is complicated.

I know there is Webpack people out there that are like, "No, It's not." I'm here to tell you that, yes. Yes, it is very, very complicated. Oh, my god.

Anyway, I just was on this project that's like, okay, there are three config files. They all do different things. The entry point, no, that's not where you point it. That's way over here. Anyway, I finally get some stuff going, and then I needed to add Sass to it, so I kind of figured out that, which means that on any Sass file, there are three loaders that you need.

You need the CSS loader, which is the thing that turns it into a style tag, I think, so that hot modular reloading works. You need a style loader, or maybe that's the one that turns into the style tag. The CSS loader is just the thing that teaches it about CSS, period. Then you need the Sass loader, but that has to come last because that deals with the actual syntax of Sass somehow. I finally got that going.

Then it found a WAF file in there because I did a font face thing, you know. So, it finds the URL to the thing. It's like, I don't know how to deal with that. [Laughter] There are all these threads and you're like, "Well, you need a resource URL loader for that."

I'm like, "What? Okay." But that's not part of the CSS loading. That goes somewhere else in the config, so it knows how to deal with when it finds a file like that.

Then I had to specially configure it because then it had an error because it couldn't figure out what to do with an SVG file, too, that I used as a background image in the CSS. That had to be configured, too, to work. I'm like, this is a lot.

Dave: Mm-hmm.

Chris: For the very simple thing I was trying to do with it. Of course, this was 48 hours of trial and error too. This wasn't just an, "Oh, I'm having a little trouble. I've got to Google something," and then I fix it. It was a lot of stopping and starting processes and getting frustrated and having 15 tabs open referencing different things. I'm just saying. I'm just saying Webpack, if that's what -- [laughter] in the context of this question from Dylan about a very simple tool that just minifies your stuff. I wouldn't go that route.


Dave: You know it's interesting. I watched Learn with Jason, Jason Lengstorf. It was Chris Biscardi was on it, party-corgi. They were demoing Chris's new project called Toast, which is sort of like a static site generator but it's ES module first. I was watching this live stream because he did one on machine learning and it was very enjoyable. Then I just was like, "Oh, I know Chris, so I'm going to watch this."

It was cool but it was also the first -- I don't know 45 minutes of the hour-long stream was just undoing Webpack. It was like, "Okay, that broke because we don't have Webpack anymore," or "That broke because you don't have this." It looked really tedious, but they were all very calm in the post. They were like, "We are undoing. We are basically jettisoning from Gatsby entirely, so these are the problems we're having."

If you rip something out, you have to run it, find the bugs, fix the bugs, then run it again. It's a very iterative -- I thought it was very real to life on how most Web development works. But it didn't make it look super easy.

Chris: That's nice.

Dave: It's kind of interesting to think about these more ES module focused, like what did Webpack do? It did the bundling, right? Or it kind of managed your imports and put require syntax in the browser. Now we have an import syntax, so maybe we can, I don't know, kind of break away from Webpack.

Anyway, it's called Toast is the project. I can't super vouch for it. I haven't really used it, but it's interesting that--

Chris: How do you Google it, because Toast won't work? Toast what?

Dave: Here, I can post a link in the chat in here. I'll put a link there. But, yeah, it's just basically a GitHub repo, so Yarn install and then you kind of use that tool to kind of build stuff. It's built-in Rust, I believe, so it should be fast.

Chris: Yeah.

Dave: It has SnowPack is mixed in there. It sort of lost me.

Chris: Do you like these? I just put together a little stack of predetermined choices in there. That's kind of what Redwood is, right? We've kind of thumbs up that in previous shows. I'm kind of a fan of it. People are like, "Let me tell you about this little stack I like.

Dave: Yeah.

Chris: It's like five things they picked out. One of them is templating. One of them is data. One of them is build process.

Dave: Yeah.

Chris: I think it's kind of fun, you know.

Dave: No, I hope we have more of that. I think even Zach Weatherman, the overload of 11ty, would agree. Having a few static site generators actually works out really well to having more options. You can at least -- you have these different tools to build these different things. Good stuff will shake out. It may take a few decades, but it will. It'll happen.


Chris: Yeah. Yeah. You know what? I was thinking of something that has shaken out. What was it? It went right into my mind, but it might have to do with Dylan's question a bit about something like--

You know I was reading a post about structuring CSS and the assumption was Sass because then you can split CSS into multiple files, which seems to be like that's the thing that no other tool has hopped in and stolen from Sass. You know what I mean?

Dave: Yeah. Okay.

Chris: That's the thing. Now it's a lot of years later. I was like, you know, I was starting to use Sass at Wufoo, like a long time ago in my career. Now, these days, I still use the Sass syntax. Sass has really shaken out as an industry-standard in a lot of ways. Even when you use something like a lot of these libraries that are CSS and JS. A lot of them just support the Sass syntax too.

Dave: Yeah. Yeah.

Chris: I've just been really surprised by that, how strongly that's held on as a syntax.

Dave: Vue has it built in. [Laughter] You do style.

Chris: Yeah.

Dave: Lang=scss or something.

Chris: SCSS, yeah. Right. Pretty powerful thing that's kind of held on there and, certainly, like minifying all your tools and all that kind of stuff.

Dave: Well, and I think--

Chris: Dylan, good luck finding that thing. I don't know that it exactly works in your favor. Also, minifying HTML always scares me a little bit, so please be careful with that. That can definitely lead to unexpected results.

Dave: Yeah. Yeah, I bailed out on it recently because it was like, I don't like what's happening. There's too much question marks happening, but I know. I should just not be afraid. But anyway.

Chris: But it's nice that we're ending the show where we started a little bit with build process-y kind of stuff. I do think that the world of build process is going to shake out in a similar way but there's stuff, like optimizing images, although that's a nuanced topic, too, that I think all the websites can benefit from. Serving minified CSS, every website on planet Earth needs that and should have that.

I think the world of build process is going to shake out. There are going to be standard ways to handle this and there are different places in the stack of serving a website where that kind of thing can happen, but there are certain things that are not specialized to any particular website. They're useful for everybody.

Dave: Yeah. Maybe -- that would be cool. What's the standard build machines or whatever? I don't know.

All right, well, hey, I've got a meeting, so we've got a hard stop.

Chris: Yeah.

Dave: Yeah, we're good. All right. Thank you, dear listener, for downloading this in your podcatcher of choice. Be sure to star, heart, favorite it up. That's how people find out about the show.

Follow us on Twitter, @ShopTalkShow, for tons of tweets a month.

If you hate your job, head over to and get a brand new one because people want to hire people like you.

Chris, do you have anything else you'd like to say?

Chris: Hmm.