Web Standards

Don’t put pointer-events: none on form labels

Css Tricks - Fri, 02/12/2021 - 10:03am

Bruce Lawson with the tip of the day, warning against the use of pointer-events: none on forms labels. We know that pointer-events is used to change how elements respond to click, tap, hover, and active states. But it apparently borks form labels, squashing their active hit target size to something small and tough to interact with. Bruce includes examples in his post.

That’s not the striking part of the post though. It’s that the issue was pinned to an implementation of Material Design’s floating labels component. Bruce fortunately had pointer events expert Patrick Lauke’s ear, who pointed (get it?) out the issue.

aha, now i remember when i first saw a few weeks ago – testing something based on material design for web https://t.co/YkEKXkU0To pic.twitter.com/31S74X1i4R

— patrick h. lauke #toryScum #clapForFlagWankers (@patrick_h_lauke) February 5, 2021

That isn’t a dig at frameworks. It’s just the reality of things. Front-end developers gotta be aware, and that includes awareness of third-party code.

Direct Link to ArticlePermalink

The post Don’t put pointer-events: none on form labels appeared first on CSS-Tricks.

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

Responsible Web Applications

Css Tricks - Fri, 02/12/2021 - 10:03am

Joy Heron bought a cool domain name and published an article there:

Luckily, with modern HTML and CSS, we can create responsive and accessible web apps with relative ease. In my years of doing software development, I have learned some HTML and CSS tips and tricks, and I want to present these in this post. This list is not exhaustive, but these are tried and true patterns that I frequently use in different projects.

Sure, it’s a collection of tips and tricks, but it’s a great one that covers modern best practices across HTML, CSS, and JavaScript. If someone asked me what they should read if they missed out on the last, say, three years of front-end and wanted to remind themselves of the important stuff, I’d send them this.

I like the casual use of a massive shape-outside in the header.

Direct Link to ArticlePermalink

The post Responsible Web Applications appeared first on CSS-Tricks.

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

Reconciling Editor Experience and Developer Experience in the CMS

Css Tricks - Fri, 02/12/2021 - 5:56am

Components are great, aren’t they? They are these reusable sources of truth that you can use to build rock-solid front-ends without duplicating code.

You know what else is super cool? Headless content management! Headless content management system (CMS) products offer a content editing experience while freeing that content in the form of data that can be ported, well, to any API-consuming front-end UI. You can structure your content however you’d like (depending on the product), and pull that content into your front-end applications.

Using these two things together — a distributed CMS solution with component-based front-end applications — is a core tenet of the Jamstack.

But, while components and headless CMSs are great on their own, it can be difficult to get them to play nicely together. I‘m not saying it‘s difficult to hook one up to the other. In a lot of cases, it’s actually quite painless. But, to craft a system of components that is reusable and consistent, and to have that system maintain parity with a well-designed CMS experience is a difficult thing to achieve. It’s that win-win combo of being able to freely write content and then have that content structured into predictable components that makes headless content management so appealing.

Achieving parity between a CMS and front-end components

My favorite demonstrating this complexity is a simple component: a button. Let‘s say we’re working with React to build components and our button looks like this:

<Button to="/">Go Home</Button>

In the lovely land of React, that means the <Button> component has two props (i.e. properties, attributes, arguments, etc.) — to and children. children is a React thing that holds all the content within the opening and closing tags, which is “Go Home” in this case.)

If we’re going to enable users in the content editor to add buttons to the site, we want a system for them that makes it easy to understand how their actions in the CMS affect what appears on screen in the front-end app. But we also want our developer(s) to work productively with component properties that make sense to them and within the framework they’re working (i.e. React in our example).

How do we do that?

We could…

…use fields in the CMS that match the components’ properties, though I’ve had little success with this approach. to and children don‘t make much sense to content editors trying to build a button. Believe me, I‘ve tried. I‘ve tried with beginners and experienced editors alike. I‘ve tried helper text. It doesn’t matter. It’s confusing.

What makes more sense is using words editors are more likely to understand, like label or text for children and url for to.

&#x1f615; &#x1f913;

But then we’d be out of sync with our code.

Or what if we…

masked attributes in the CMS. Most headless CMS solutions enable you to have a different value for the label of the field than the name that is used when delivering content via an API.

We could label our fields Label and URL, but use children and to as the names. We could. But we probably shouldn’t. Remember what Ian Malcolm said?

On the surface, masking attributes makes sense. It’s a separation of concerns. The editors see something that makes them happy and productive, and the developers work with the names that make sense to them. I like it, but only in theory. In practice, it confuses developers. Debugging a content editor issue often requires digging through extra layers (i.e. time) to find the relationship between labels and field names.

Or why not …

…change the properties. Wouldn’t it be easier for developers to be flexible? They’re the ones designing the system, after all.

Yes, that’s true. But if you follow that rule exclusively, it’s inevitable that you’re going to run into some issue along the way. You’ll likely end up fighting against the framework, or props will just feel goofy.

In our example, using label and url as props for a button works totally fine for data that originates from the CMS. But that also means that any time our developers want to use a button within the code, it looks like this:

<Button label="Go Home" url="/" />

That may seem okay on the surface, but it significantly limits the power of the button. Let’s say I want to support some other feature, like adding an icon within the label. I’m going to need some additional logic or another property for it. If I would have used React’s children approach instead, it would have just worked (likely after some custom styling support).

Okay, so… what do we do?

Introducing transformers

The best approach I’ve found is to separately optimize the editor and developer experiences. Craft a CMS experience that is catered to the editors. Build a codebase that is easy for developers to navigate, understand, and enhance.

The result is that the two experiences will not be in parity with one another. We need some set of utilities to transform the data from the CMS structure into something that can be used by the front-end, regardless of the framework and tooling you’re using.

I call these utilities transformers. (Aren’t I so good at naming things!?) Transformers are responsible for consuming data from your CMS and transforming it into a shape that can be easily consumed by your components.

While I‘ve found that transforming data is the smoothest means to get great experiences in both the CMS and the codebase, I don‘t have an obvious solution for how (or perhaps where) those transformations should happen. I‘ve used three different approaches, all of which have their pros and cons. Let’s take a look at them.

1. Alongside components

One approach is to put transformers right alongside the components they are serving. This is the approach I typically take in organizing component-based projects — to keep related files close to one another.

That means that I often have a directory for every component with a predictable set of files. The index.js acts as the controller for the component. It is responsible for importing and exporting all other relevant files. That makes it trivial to wrap the component with some logic-based behavior. In other words, it could transform properties of the component before rendering it. Here’s what that might look like for our button example:

import React from "react" import Component from "./component" import transform from "./transformer" const Button = props => <Component {...transform(props)} /> export default Button

The transform.js file might look like this:

export default input =&gt; { return { ...input, children: input.children || input.label, to: input.to || input.url } }

In this example, if to and children were properties sent to the component, it works just fine! But if label and url were used instead, they are transformed to children and to. That means the <Button> component (component.js) only has to worry about using children and to.

const Button = ({ children, to }) => <a href={to}>{children}</a>

I personally love this approach. It keeps the logic tightly coupled with the component. The biggest downside I‘ve found thus far is that it’s a large number of files and transforms, when the entire dataset for any given page could be transformed earlier in the stack, which would be…

2. At the top of the funnel

The data has to be pulled into the application via some mechanism. Developers use this mechanism to retrieve as much data for the current page or view as possible. Often, the fewer number of queries/requests a page is required to make, the better its performance.

In other words, that mechanism often exists near the top of the funnel (or stack), as opposed to each component pulling its own data in dynamically. (When that’s necessary, I use adapters.)

The mechanism that retrieves the page data could also be responsible for transforming all the data for the given page before it renders any of its components.

In theory, this is a better approach than the first one. It decreases the amount of work the browser has to do, which should improve the front-end performance. That means the server has to do more work, but that’s often a better choice.

In practice, though, this is a lot of work. Data structures can be big, complex, and interwoven. It can take a heck of a lot of work to transform everything into the right format at the top of the funnel, and then pass the transformed data down to components. It’s also more difficult to test because of the potential complexity and variation of the giant data blob retrieved at the top of the stack. With the first approach, testing the transformer logic for the button is trivial. With this approach, you’d want to account for transforming button data anywhere that it might appear in the retrieved data object.

But, if you can pull it off, this is generally the better approach.

3. The middleman engine

The third and final (and magical) approach is to do all this work somewhere else. In this case, we could build an engine (i.e. a small application) that would do the transformations for us, and then make the content available for the application to consume.

This is likely even more work than the second approach. And it has added cost and maintenance in running an additional application, which takes more effort to ensure it is rock solid.

The major upside to this approach is that we could build this as an abstracted engine. In other words, any time we bring in data to any front-end application, it goes through this middleman engine. That means if we have two projects that use the same CMS or data source, our work is cut down significantly for the second project.

If you aren‘t doing any of this today and want to start, my advice is to treat these approaches like stepping stones. They grow in complexity and maintenance and power as the application grows. Start with the first approach and see how far that gets you. Then, if you feel like you could benefit from a jump to the second, do it! And if you’re feeling like living dangerously, go for the third!

In the end, what matters most is crafting an experience that both your editors and your developers understand and enjoy. If you can do that, you win!

The post Reconciling Editor Experience and Developer Experience in the CMS appeared first on CSS-Tricks.

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

The Devil’s Albatross

Css Tricks - Fri, 02/12/2021 - 5:54am

Nils Binder talks about a technique for spacing between two elements. Picture a header on a large screen with a logo in the upper left and nav in the upper right. Then a small screen, when they can no longer be on the same “row” and need to wrap, they don’t just wrap but are centered.

A video explains better:

My mind goes: I’d just find the exact pixel value for the breakpoint I want this to happen and then write a media query that re-styles things to do that.

But… media queries are only for the entire browser window width. While that probably works in a case like this because it’s a full-site kinda concern, I get the desire to not have to write media queries. Nils’ idea borrow concepts from Heydon’s Holy Albatross to make this work without any media queries at all. So, you could use this on a smaller-scope component where you need to adjust the breaking point at a certain size that has nothing to do with the size of the browser window.

CodePen Embed Fallback

Direct Link to ArticlePermalink

The post The Devil’s Albatross appeared first on CSS-Tricks.

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

Is CSS float deprecated?

Css Tricks - Thu, 02/11/2021 - 1:21pm

An interesting conversation came up at work the other day: Should we use the CSS float property now that we have CSS Grid and Flexbox?

The short answer

No! Well, mostly. I’d only use it today for wrapping text around images, though and I’d avoid using float entirely for layouts.

The longer, more annoying answer

Before flexbox and grid, we had to use the CSS float property to make grids and layouts. In fact, it was the first thing I learned about web design. On one hot summer afternoon I cracked open a copy of Designing with Web Standards by Jeffrey Zeldman and then moved a tiny red div with float: right. It was magic. There was power in the float.

It was so easy to move something around on the screen that I now wonder how many designers fell in love with the web simply because of how easy it is to use move things around like that.

But using float to build complex layouts was always a hack: it was only really designed to let text wrap around an image.

img { width: 150px; float: left; } CodePen Embed Fallback

The problems with float begin when we try to build giant layouts and magazine-style grids. But that’s what we had to do since there were no alternatives back then like we do today.

One problem with the float property is that you’d have to wrap floated elements with something called a clearfix that looked like this:

<div class="clearfix"> <div class="float-left">Column</div> <div class="float-left">Column</div> <div class="float-left">Column</div> </div> clearfix:after { content: ""; display: table; clear: both; }

Jay Hoffman described the clearfix hack a while back:

The clearfix, for those unaware, is a CSS hack that solves a persistent bug that occurs when two floated elements are stacked next to each other. When elements are aligned this way, the parent container ends up with a height of 0, and it can easily wreak havoc on a layout. All you might be trying to do is position a sidebar to the left of your main content block, but the result would be two elements that overlap and collapse on each other. To complicate things further, the bug is inconsistent across browsers. The clearfix was invented to solve all that.

Things began to slowly change after that. Back in 2017, Rachel Andrew explained how browsers can handle the clearfix problem without any hacks at all. All we need is the following CSS to make the same fix:

.container { display: flow-root; }

The odd thing is that I didn’t know the flow-root value existed until about three minutes before I typed that. But I guess this sort of defends the argument I’m about to make here: with CSS Grid and Flexbox we don’t really need float at all. The property was really designed to do one thing: let text wrap around images. But now, with grid and flexbox, we have wonderful powers that can do all the heavy lifting for real layouts.

Back to the argument I was having at work. Some folks said that we should go back and delete all the instances of float in our codebase because it’s old code and we can easily replace it with flexbox or grid. But this is where I’d say, Whoa! hold up a sec. I don’t think having the float property in a few places in our codebase is doing that much harm at all — this isn’t radioactive code that’s causing problems.

So should we be using CSS float for anything besides letting text wrap around text? Nope. But should we all go out and immediately purge the web of CSS float declarations because it’s not pure and not the “correct” way of doing things? Nope again.

The nifty thing about the web is that old code shouldn’t break things. Just ask Chris. A website that isn’t using the fanciest CSS properties or the coolest tricks isn’t useless or bad. We’ve simply replaced float with alternatives that are better. I think it’s a good lesson here that these CSS properties are likely going to stick around forever because they still have applicable use cases in modern web design.

And that’s okay.

The post Is CSS float deprecated? appeared first on CSS-Tricks.

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

Progressive Web Apps in 2021

Css Tricks - Thu, 02/11/2021 - 1:21pm

Maximiliano Firtman has a look at PWAs this year, including trying to get a bead on how widespread they are:

At the end of 2020, approximately 1% of websites included a Service Worker, and 2.2% had an installable Web App Manifest file. Remember that some platforms -such as Safari on iOS or Chrome on Android- do not require a Service Worker to have a standalone experience after installation. We can assume that 2.2% of websites are installable, and 1% may pass the PWA criteria on Android, 71% of which offer some offline experience.

That data is from the HTTP Archive, which looked at 7.5 million websites. So 1% might seem like a small number, but that’s lots of sites with PWA tech on them, and 170% year-over-year growth. Those are just the minimum requirements, though. I’m sure fully embracing PWA-ness (e.g. real offline usage) is a tiny fraction of that. Maximiliano has lots of more detailed data, so be sure to dig into the article if you’re interested in the nuance.

Anecdotally, I’d say PWAs fell out of general conversation last year. I don’t think anybody is exactly against the technologies that make them up, but they aren’t embracing them either. My guess? Everyone is scared of Service Workers. I’m scared of Service Workers. They do scary things, like aggressively hold onto cache. I think a whole dev team really needs to understand them and embrace them into their workflow and build process for them to be effective. Generally speaking, we just aren’t there yet.

Direct Link to ArticlePermalink

The post Progressive Web Apps in 2021 appeared first on CSS-Tricks.

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

WordPress 5.7: Big ol’ jQuery Update

Css Tricks - Thu, 02/11/2021 - 6:08am

WordPress core is making the jump from jQuery 1.12.4 to jQuery 3.5.1! This is a big deal for lots of reasons — like modern features, better DX, and security improvements to name a few. Right now, the plan is to release the update in WordPress 5.7, which is slated to release on March 9. &#x1f91e;

WordPress is notorious for its backwards compatibility and you could say this change is a relic of that philosophy. A line has been drawn in the sand when it comes to jQuery, and 1.x ain’t a part of plans moving forward. But it also represents a breaking change, and that’s sorta rare in the WordPress world. Because WordPress ships with jQuery installed, many developers call that version of it rather than re-installing it in another location. That includes lots of theme and plugin developers, all of whom now need to make sure their code is compatible with jQuery 3.x.

Not doing so could result in lots on borked sites. But, hey, we have about a month left to work on it, right?

The change has actually been in the works for some time. The work began in WordPress 5.5, and 5.7 is technically the third of three phases. WordPress 5.6 is where the Core Team bumped jQuery up to version 3.5.1 and updated jQuery Migrate to help developers revert back to legacy jQuery, if needed. In other words, this has been a super methodical approach. The Core Team deserves a lot of kudos for that, including all of the communications that have gone out about the change.

I wrote something up about the transition a couple of weeks ago, including a sort of how-to for testing things in advance, and troubleshooting issues after the fact. It’s aimed at beginners, but maybe you’ll find it helpful too. Make WordPress Support has its own thorough article as well, and it calls out a plugin that the WordPress team made just for this transition. It’s pretty sweet: it can roll your site back to jQuery1.x automatically if it detects a fail. It also documents those fails and sends notifications when they happen.

The key is to start testing now in WordPress 5.6. The plan is to disable jQuery Migrate in WordPress 5.7, so waiting for that release is too late. If you do wait that long and find issues, your best path forward is likely to roll back to 5.6 anyway to take advantage of jQuery Migrate and the helper plugin.

The post WordPress 5.7: Big ol’ jQuery Update appeared first on CSS-Tricks.

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

iframe feedback

Css Tricks - Thu, 02/11/2021 - 4:24am

What if an <iframe> had within it another <iframe> of the exact same source? Inception, as they say. Baptise Crespy does this all-important research in the name of art and science.

Turns out browsers are smart enough to not allow this infinite looping to occur (and likely crash your browser/computer). They strip the content after the 2nd nest. But! If you change the URL of the src to be unique (but still essentially serve the same document), it works. Adding some random colors and animations and things get weird really fast.

Motion warning video:

Direct Link to ArticlePermalink

The post iframe feedback appeared first on CSS-Tricks.

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

Progressive Enhancement reading list, draft 1

QuirksBlog - Thu, 02/11/2021 - 1:24am

In March I am going to teach the Progressive Enhancement course of the Web minor at university for the third time. I decided to expand the reading list for this course, and here I presented draft 1 and asked for feedback.

Meanwhile the reading list is done and I removed this draft. Also, I have a question about progressive enhancement and accessibility that I wasn't able to solve.

HTML Video Sources Should Be Responsive

Css Tricks - Wed, 02/10/2021 - 1:40pm

Scott Jehl doesn’t mince words here:

Removing media support from HTML video was a mistake. It means that for every video we embed in HTML, we’re stuck with the choice of serving source files that are potentially too large or small for many users’ devices (resulting in poor performance, wasteful data consumption, and even sub-optimal quality on larger screens), or resorting to more complicated server-side or scripted or third-party solutions to deliver a correct size.

I remember when responsive images were just starting to come out. One way to explain it was to say it’s like <video> in that you can have multiple <source> elements inside which (in supporting browsers) allowed you to specify attributes like type (e.g. video format) and media (e.g. screen size). But then

Despite being implemented in multiple browsers, the feature was removed from browsers and the HTML specification, without any proposed replacement for the functionality it once provided. One exception is the feature was never removed from Webkit, so it still works in Safari browsers, which is great.

I don’t remember that. That feels like a big WTF moment (some background). I think of the web as being tremendous at backwards compatibility. It’s a rare day when we just yank stuff, and even more rare is a yanking with no alternative whatsoever.

So now with responsive images being a success (it’s a success, right? I can’t imagine how incredibly much bandwidth it has saved the world)… can’t we… put it back?

When I have an immediate need for this, I always think of Cloudinary, because I can alter the size and format of video by changing the URL. Like here’s a video URL where the video codec is automatically determined and the size is forced down to 400px:

https://res.cloudinary.com/css-tricks/video/upload/c_scale,q_auto,vc_auto,w_400/v1612795501/intro-patreon_jpd8er.mp4

It’s nice to have tools like this, but that doesn’t mean the platform shouldn’t be helping.

Direct Link to ArticlePermalink

The post HTML Video Sources Should Be Responsive appeared first on CSS-Tricks.

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

:focus-visible Support Comes to Firefox

Css Tricks - Wed, 02/10/2021 - 10:51am

Look at that! The :focus-visible pseudo-selector is now supported in Firefox, as of version 85 which shipped yesterday. I had to rush over to the MDN Docs just to confirm, and yep, the :focus-visible page has been updated to reflect the news.

What’s so cool about :focus-visible? It’s all about the blue focus ring that displays around elements that are in focus. It’s sort of a happy medium between loving the outline for accessibility purposes (gotta know what element is selected when tabbing on a keyboard) but not-really-loving how it looks (gotta have everything follow brand).

The strategy has largely been an all-or-nothing choice between using a custom outline when any element is in :focus (great, but that means for both keyboard tabbing and mouse clicks) or ditching the outline altogether (not great, like ever). :focus-visible accomplishes the same thing as :focus, but uses a browser’s knowledge of user inputs (or heuristics) to determine whether the focus is coming from a keyboard or a mouse.

(Are a browser’s heuristics perfect at determining the input? That depends. Things get murky once we start factoring in things like touch interactions.)

That means, we get to remove the default focus ring (yay!) for the right types of interactions (double yay!) and display our own custom styles while we’re at it (triple yay!). Allow me to pluck Andy Adams’ fine example straight from our almanac. Note that :focus-visible cannot remove the focus ring like :focus can, so the two are used together:

.next-image-button:focus { outline: none; } .next-image-button:focus-visible { outline: 3px solid blanchedalmond; /* That'll show 'em */ } CodePen Embed Fallback

Chrome implemented :focus-visible back in 2018. Firefox had it’s own prefixed version, :-moz-focusring, prior to this implementation. Safari? Go vote for the feature!

Igalia is gathering funding and working on getting it into Safari! Here’s Brian Kardell on this.

The post :focus-visible Support Comes to Firefox appeared first on CSS-Tricks.

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

How to Favicon in 2021

Css Tricks - Wed, 02/10/2021 - 8:21am

I always appreciate someone looking into and re-evaluating the best practices of something that literally every website needs and has a complex set of requirements. Andrey Sitnik has done that here with favicons.

The final suggestion:

<link rel="icon" href="/favicon.ico"><!-- 32×32 --> <link rel="icon" href="/icon.svg" type="image/svg+xml"> <link rel="apple-touch-icon" href="/apple-touch-icon.png"><!-- 180×180 --> <link rel="manifest" href="/manifest.webmanifest"> { "icons": [ { "src": "/192.png", "type": "image/png", "sizes": "192x192" }, { "src": "/512.png", "type": "image/png", "sizes": "512x512" } ] }

It was good timing to do this here on CSS-Tricks, so I tried following the advice to the letter, and it’s working great so far. I think I got fed up at how complex it was at some point that I went ultra-minimalist and only had favicon.ico file. Now I’ve got all of the above in place.

Where I differed…

  • I don’t have GIMP or Inkscape installed, which can export .ico format, so I used this favicon generator (I fed it my “main” SVG”) just for that one icon.
  • I found Figma helpful for resizing frames and exporting the right sizes.
  • I used ImageOptim for optimizing all the images.
  • I was nervous about adding a “manifest” because I don’t have any other PWA-like steps in place and it feels like an extra web request for little value. But I did it anyway.
  • I have a theme color (<meta name="theme-color" content="rgb(255, 122, 24)">) because I was told it was a nice touch. Feels related.

I love the dark mode SVG concept:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500"> <style> @media (prefers-color-scheme: dark) { .a { fill: #f0f0f0 } } </style> <path class="a" fill="#0f0f0f" d="…" /> </svg>

But I didn’t do any trickery there as I think my icon looks fine either way without changes:

I also haven’t gotten around to making a special development-only favicon again, but I will because I find it extremely handy.

Direct Link to ArticlePermalink

The post How to Favicon in 2021 appeared first on CSS-Tricks.

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

The Differences in Web Hosting (Go with the Happy Path)

Css Tricks - Wed, 02/10/2021 - 5:46am

One of our readers checked out “Helping a Beginner Understand Getting a Website Live” and had some follow up questions specifically about hosting providers. Here’s what they asked:

What’s the difference between hosting providers? For example, what is the difference between GoDaddy and Hostgator, which seems like “traditional” web hosting providers, to others like Heroku, Digital Ocean, AWS, and Firebase?

When would I use one over the other?

They were hoping for detailed thoughts, so I’m going to oblige!

Choosing a plan

You mentioned GoDaddy first, so let’s take a peak at GoDaddy’s hosting offerings as I type:

To be honest, I’m already confused. (Sorry, I promise I’ll try to be more helpful as we go on.) Why is WordPress hosting one dollar more expensive than the Web Hosting plan? If you buy the $5.99 Web Hosting plan are you prevented from installing WordPress on it? Or is it just convenient in that if you pick the WordPress hosting it comes pre-installed and configured? WooCommerce is just a plugin for WordPress, so are you prevented from installing that on the WordPress hosting plan until you upgrade to the WordPress Ecommerce Hosting plan? (To be fair, WordPress.com unlocks WooCommerce at the highest plan as well, so it’s trod territory.) Why is the VPS Hosting plan the cheapest? I don’t blame you if you also find this as confusing as I do, especially as this is just one of many different charts of hosting options they offer.

GoDaddy makes a billion zillion dollars a year, so I’m sure they’ve got this stuff figured out, but I’ll tell ya, after a couple of decades of web development experience, I’d be totally guessing at choosing a plan from options like this. Cynically, it feels like confusion might be a sales tactic.

Technology

I do know this: these plans are for PHP / MySQL sites. That means WordPress, Craft, Perch, Ghost, Drupal, Joomla, etc. This is the LAMP stack which has all the big CMSs covered. Just the way it is. This is going to be the case at Media Temple, Hostgator, Bluehost, and lots of hosts like that. I think a “traditional” web host, as you put it, isn’t a bad way to think about it.

Do you wanna run PostgreSQL or MariaDB instead of MySQL? Or you wanna run ASP instead of PHP? I’ll bet you all these hosts have some kind of answer for those things. The answer is going to be something like “Don’t use our shared hosting product, use our raw VPS (‘Virtual Private Server’) product which has direct root access, and you can install it yourself.” I guess that’s fine, but just know those things aren’t first-class citizens of their hosting. If you have trouble, I’d worry you’ll have a hard time getting good support.

Which leads me to my point: you should go with the happy path offerings from hosting providers.

Say I want to write a Python app. I’m not going to buy a Hostgator server. I’m sure you can get it to work, but it’s not something they really promote. It doesn’t feel like it’s on a happy path. Whereas if I look around at Heroku, they make it a first-class citizen of what they offer:

I can’t vouch for it directly as I’ve never used Heroku, but I’ve heard lots of good things and they’ve been doing this for a good 15 years.

Happy paths are about friendly pairings

Heroku reminds me of another divide in hosting providers that I think is significant. Those “traditional” web hosts don’t lift a finger to help you get your websites over to them. It’s more like: here’s your FTP credentials, good luck. With a host like Heroku, they are giving you a CLI to like heroku container:push to deploy your local code to production. Better, it will deploy right from your GitHub repository. Why every single web host in the world doesn’t help with that is a mystery to me. A web host that helps you with deployment is a valuable thing.

We were talking about happy paths, right? Heroku calls themselves a “Cloud Application Platform.” The happy path there is those server-y languages. Node, Ruby, Python, Go. What if you don’t need any of that? Say you’re building a static site, using a static site generator (like Eleventy) at the core (Jamstack, as it were). Do you pick Heroku? Probably not. While surely you could pull it off on Heroku, static site hosting isn’t core to Heroku, and so not a happy path.

Where should you host a static site? That’s Netlify’s whole ball game. Netlify is a super happy path for static sites.

In fact, Netlify nailed the Jamstack-style hosting thing so strongly that lots of companies have been trying to provide similar offerings. I think of Azure’s Static Web Apps as an example. So why use Azure over Netlify? If it feels like a happy path, and it might if you’re using other Azure products, assuming their products play well together. Azure is a massive cloud platform with loads of other offerings. Or you might just have more experience and developer muscle memory for Microsoft products. We’ll get to that later.

Jamstack (essentially meaning static hosting + services) is available in lots of places now. Cloudflare has Cloudflare Pages, which you might take advantage of because of the unlimited promises (unlimited sites, unlimited requests, unlimited bandwidth, and even unlimited team seats).

You might choose Cloudflare Pages because your Cloudflare products like access or workers that are important to you and it feels like the happy path to keep it all together.

Vercel has Jamstack hosting, but they’ll run servers for you if you need them. Their popular framework, Next.js, prebuilds pages, but can also deliver server-side rendered pages with a Node back end. Vercel gives you that back end.

Next.js on Vercel is a very happy path. “Deploy on the platform made for Next.js,” they say. Hard to beat that.

AWS Amplify is ultimately Jamstack hosting, and the happy path there is using Amplify to stitch together other AWS services. That’s literally the point of AWS Amplify.

Need auth? It’s Amazon Cognito under the hood, but Amplify helps you stitch it into what you are doing. Need storage? S3 is an industry standard, and Amplify helps you integrate it. Need a database? Amplify helps you model it and build APIs.

Firebase has Jamstack-style hosting, and the happy path is leaning into the Firebase framework.

Firebase has lots of very useful features, like real-time data storage, authentication, and RUM analytics. If I wasn’t using any of those things, I’m not sure I’d pick Firebase hosting. Like for a basic Jekyll blog, can it be done? Absolutely. Would I personally do it? Probably not. It’s not really leaning into the Firebase offerings, making it way less of a happy path.

It’s worth talking about &#x1f4aa; developer “muscle memory” for a moment. You build muscle memory for the things you do a lot. If you’ve got five sites on Netlify already, and you’ve gone through those motions over and over, it makes sense that your sixth site is on Netlify as well — even if some other host might be a slightly better fit. Knowing your tools well and feeling comfortable is a big deal. You can compare pricing and features and all the bits and bobs, but muscle memory is one of the most powerful choice influences, and I think that’s perfectly fine.

Your host should take care of your core needs

Remember how I mentioned a web host that helps you with deployment is a valuable thing? All of these hosts do that: Netlify, Vercel, AWS Amplify, Google Firebase, Cloudflare Pages, Azure Static Sites. That’s become table-stakes for hosting providers. There are more table-stakes as well.

The table stakes of modern web hosts.

Beyond, ya know, hosting the website.

  1. HTTPS. The host should give my site an SSL certificate. Probably automatically, and probably for free (since Let’s Encrypt is free).
  2. CDN. The host should help serve as much as my site as is practical from a CDN, even if it’s a paid feature or requires configuration.
  3. Deployment. The host should connect to Git repositories and move files from the main branch to the production site.
  4. Staging. The host should provide staging environment(s).

I should circle back to the WordPress (and other PHP/MySQL CMS) thing. That’s what this site is. Traditional hosts serve this market. WordPress is 35.2% of all websites, which is bananas, and means there are wheelbarrows full of money in that hosting market. But in my experience, the traditional hosts do almost none of what I just called table stakes in hosting. A lot of times, you’re on your own for HTTPS. You’re on your own for integrating a CDN. You’re on your own for deployment. Staging just means buy another server. It’s just a weird time for hosting right now, with such a wide gap in modern web hosts doing so much and traditional web hosts doing so little.

That’s not true of all WordPress-specific hosts though. Using a WordPress-specific host for hosting WordPress is about as happy path as you can get. I’m on Flywheel now and appreciate all they do. They cover that entire list of table stakes, and go further still, helping with local development.

You asked about Digital Ocean specifically…

I feel the least qualified to explain Digital Ocean, but I think it’s fair to say that Digital Ocean has a lot of happy paths. They have this concept of a “Droplet” (it’s a server) which is spun up from “containers.” I wouldn’t worry terribly much about the idea of containers at this point, but suffice it to say, they are pre-configured servers that can run any sort of combination of technologies. If you want to fire up a LAMP stack thing in a Droplet, that’s a first-class citizen. But so are lots of other technologies. Consider Strapi, a CMS that is Node, Nginx, and PostgreSQL. Digital Ocean has a Droplet for that’s ready for it out of the box.

Droplets also start at $5/month, so they are just as economical as other hosts, if not more so. You might find hosting products that are actually Digital Ocean under the hood! For example, the WordPress hosting tool SpinupWP allows you to quickly create configured WordPress hosting environments, but it doesn’t do the hosting itself, you “bring your own” host, which is likely Digital Ocean or AWS (Amazon Web Services).

It only gets more complicated from here

If Digital Ocean seems complex, wait until you hear about AWS. We talked about AWS Amplify earlier, but that’s like AWS designed for individual developers like you and me to scaffold apps quickly. It’s very cool, but it’s a small wedge of what all that is AWS.

AWS is this massive cloud services provider, meaning that, sure, you can spin up web servers, but there are also hundreds of other services for things, like databases, storage, serverless stuff, APIs, logs, heck — you can rent a damn quantum computer there, which is like sci-fi stuff. It’s not that a normal developer can’t use AWS for a web host, it’s just like, not really designed with that kind of DX in mind. This guide on installing WordPress makes me sweat. AWS is super powerful, has solutions for everything, and is priced as low as it gets. Perhaps it’s useful to think of AWS as like down-to-the-metal web infrastructure, designed for large-scale operations. Web hosts might even be built on top of AWS, for example.

Matching your needs to what’s available

Let’s do some quick hits of needs matched to options. This is in no way comprehensive. I just slapped it together with things that popped to mind that feel happy path aligned.

BudgetTypicalWordPressMediaTemple / GoDaddyFlywheel or WP EngineOther PHP + MySQL (e.g. Craft CMS)BluehostCloudways or fortrabbitRuby on RailsLinodeHerokuNode.jsPut in in a LambdaDigital OceanPythonVercelHerokuGoVercelCloud RunJamstackGitHub PagesNetlify or Cloudflare PagesGraphQL APIHasuraAWS Amplify / AppSyncImage StorageS3Cloudinary

It’s worth re-iterating that there is a lot of commonality in hosting. Say you’ve got an index.html file you want to host and that’s your entire website; literally any web host will do that. These are all web hosts, after all. They serve files and run code. They aren’t that different. We’re largely talking about DX here: do they run what I need to run? Is it straightforward? Do they help make it easy? Do they clearly offer support for it?

Is it the happy path?

Then there’s pricing

We haven’t really talked much about price. I know that’s a major consideration for a lot of people and I don’t want to downplay it. But it’s hard to talk about without knowing your needs. I also don’t want people to make major web hosting decisions based on something like a few dollars difference in monthly cost. If you spend half an hour troubleshooting you otherwise wouldn’t have had to, those savings are blown.

I find that web hosting is somewhat of a commodity market. The prices are fairly stable. If a host seems expensive, it’s probably because they offer a lot. If a host seems cheap, it’s probably because they cut costs in a way you’ll eventually feel. If you’ve got a little baby site, chances are, you’re going to be hosting it for free. And if and when the site grows up, the hosting costs will feel minimal and fair.

&#x1f6e0; Does all this seem kinda fun and exciting to you? If it does, you might think about a career in DevOps dealing with servers, deployment, infrastructure, and supporting developers doesn’t have to be a side-job to other development work, it can be a whole job.

Happy happy pathing.

The post The Differences in Web Hosting (Go with the Happy Path) appeared first on CSS-Tricks.

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

A table with both a sticky header and a sticky first column

Css Tricks - Tue, 02/09/2021 - 3:06pm

We’ve covered that individual <table> cells, <th> and <td> can be position: sticky. It’s pretty easy to make the header of a table stick to the top of the screen while scrolling through a bunch or rows (like this demo).

But stickiness isn’t just for the top of the screen, you can stick things in any scroll direction (horizontal is just as fun). In fact, we can have multiple sticky elements stuck in different directions inside the same element, and even single elements that are stuck in multiple directions.

Here’s a video example of a table that sticks both the header and first column:

Why would you do that? Specifically for tabular data where cross-referencing is the point. In this table (which represents, of course, the scoring baseball game where somehow 20 teams are all playing each other at once because that’s how baseball works), it “makes sense” that you wouldn’t want the team name or the inning number to scroll away, as you’d lose context of what you’re looking at.

CodePen Embed Fallback

Not all tables need to be bi-directionally cross-referenceable. A lot of tables can smash rows into blocks on small screens for a better small-screen experience.

The “trick” at play here is partially the position: sticky; usage, but moreso to me, how you have to handle overlapping elements. A table cell that is sticky needs to have a background, because otherwise we’ll see overlapping content. It also needs proper z-index handling so that when it sticks in place, it’ll be on top of what it is supposed to be on top of. This feels like the trickiest part:

  • Make sure the tbody>th cells are above regular table cells, so they stay on top during a horizontal scroll.
  • Make sure the thead>th cells are above those, for vertical scrolling.
  • Make sure the thead>th:first-child cell is the very highest, as it needs to be above the body cells and it’s sibling headers again for horizontal scrolling.

A bit of a dance, but it’s doable.

High five to Cameron Clark who emailed me demoed this and showed me how cool it is. And indeed, Cameron, it is cool. When I shared that around, Estelle Weyl showed me a demo she made several years ago. That feels about right, Estelle is always a couple of years ahead of me.

The post A table with both a sticky header and a sticky first column appeared first on CSS-Tricks.

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

Nested Media Queries

Css Tricks - Tue, 02/09/2021 - 10:34am

Using media queries in CSS as part of responsive websites is bread and butter stuff to todays front-end developer. Using preprocessors to make them more comfortable to write and easier to maintain has become common practice as well.

I spent a few months experimenting with a dozen different approaches to media queries in Sass and actually used a few in production. All of them eventually failed to cater for everything I needed to do in an elegant way. So I took what I liked about each of them and created a solution that covered all scenarios I came across.

Why use a preprocessor at all?

That’s a fair question. After all, what’s the point of doing all this if one can simply write media queries using pure CSS? Tidiness and maintainability.

The most common use for media queries is the transformation of a layout based on the browser’s viewport width. You can make a layout adapt in such a way that multiple devices with different screen sizes can enjoy an optimal experience. As a consequence, the expressions used to define the media queries will make reference to the typical screen width of those devices.

So if your code contains 5 media queries that target tablet devices with a width of 768px, you will hardcode that number 5 times, which is something ugly that my OCD would never forgive. First of all, I want my code to be easy to read to the point that anyone understands instantly that a media query is targeting tablet devices just by looking at it – I reckon the word tablet would do that better than 768px.

Also, what if that reference width changes in the future? I hate the idea of replacing it in 5 instances around the code, especially when it’s scattered around multiple files.

A first step would be to store that breakpoint in a variable and use it to construct the media query.

/* Using plain CSS */ @media (min-width: 768px) { } /* Using SCSS variables to store breakpoints */ $breakpoint-tablet: 768px; @media (min-width: $breakpoint-tablet) { }

Another reason to write media queries with a preprocessor like Sass is that it can sometimes provide some precious help with the syntax, in particular when writing an expression with a logical or (represented with a comma in CSS).

For example, if you want to target retina devices, the pure CSS syntax starts getting a bit verbose:

/* Plain CSS */ @media (min-width: 768px) and (-webkit-min-device-pixel-ratio: 2), (min-width: 768px) and (min-resolution: 192dpi) { } /* Using variables? */ @media (min-width: $bp-tablet) and ($retina) { // or #{$retina} }

It does look nicer, but unfortunately it won’t work as expected.

A problem with logic

Because of the way the CSS “or” operator works, I wouldn’t be able to mix the retina conditions with other expressions since a (b or c) would be compiled into (a or b) c and not a b or a c.

$retina: "(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi)"; // This will generate unwanted results! @media (min-width: 480px) and #{$retina} { body { background-color: red; } } /* Not the logic we're looking for */ @media (min-width: 480px) and (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { body { background-color: red; } }

I realized I needed something more powerful, like a mixin or a function, to address this. I tried a few solutions.

Dmitry Sheiko’s technique

One I tried was Dmitry Sheiko’s technique, which had a nice syntax and includes Chris’ retina declaration.

// Predefined Break-points $mediaMaxWidth: 1260px; $mediaBp1Width: 960px; $mediaMinWidth: 480px; @function translate-media-condition($c) { $condMap: ( "screen": "only screen", "print": "only print", "retina": "(-webkit-min-device-pixel-ratio: 1.5), (min--moz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (min-device-pixel-ratio: 1.5), (min-resolution: 120dpi)", ">maxWidth": "(min-width: #{$mediaMaxWidth + 1})", "<maxWidth": "(max-width: #{$mediaMaxWidth})", ">bp1Width": "(min-width: #{$mediaBp1Width + 1})", "<bp1Width": "(max-width: #{$mediaBp1Width})", ">minWidth": "(min-width: #{$mediaMinWidth + 1})", "<minWidth": "(max-width: #{$mediaMinWidth})" ); @return map-get( $condMap, $c ); } // The mdia mixin @mixin media($args...) { $query: ""; @each $arg in $args { $op: ""; @if ( $query != "" ) { $op: " and "; } $query: $query + $op + translate-media-condition($arg); } @media #{$query} { @content; } }

But the problem with logical disjunction was still there.

.section { @include media("retina", "<minWidth") { color: white; }; } /* Not the logic we're looking for */ @media (-webkit-min-device-pixel-ratio: 1.5), (min--moz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3 / 2), (min-device-pixel-ratio: 1.5), (min-resolution: 120dpi) and (max-width: 480px) { .section { background: blue; color: white; } } Landon Schropp’s technique

Landon Schropp’s was my next stop. Landon creates simple named mixins that do specific jobs. Like:

$tablet-width: 768px; $desktop-width: 1024px; @mixin tablet { @media (min-width: #{$tablet-width}) and (max-width: #{$desktop-width - 1px}) { @content; } } @mixin desktop { @media (min-width: #{$desktop-width}) { @content; } }

He has a single-responsibility retina version as well.

But another problem hit me when I was styling an element that required additional rules on intermediate breakpoints. I didn’t want to pollute my list of global breakpoints with case-specific values just so I could still use the mixin, but I definitely didn’t want to forgo the mixin and go back to using plain CSS and hardcoding things every time I had to use custom values.

/* I didn't want to sometimes have this */ @include tablet { } /* And other times this */ @media (min-width: 768px) and (max-width: 950px) { } Breakpoint technique

Breakpoint-sass was next on my list, as it supports both variables and custom values in its syntax (and, as a bonus, it’s really clever with pixel ratio media queries).

I could write something like:

$breakpoint-tablet: 768px; @include breakpoint(453px $breakpoint-tablet) { } @include breakpoint($breakpoint-tablet 850px) { } /* Compiles to: */ @media (min-width: 453px) and (max-width: 768px) { } @media (min-width: 768px) and (max-width: 850px) { }

Things were looking better, but I personally think that Breakpoint-sass’ syntax feels less natural than Dmitry’s. You can give it a number and it assumes it’s a min-width value, or a number and a string and it assumes a property/value pair, to name just a few of the combinations it supports.

That’s fine and I’m sure it works great once you’re used to it, but I hadn’t given up on finding a syntax that was both simple and as close as possible to the way I orally describe what a media query must target.

Also, if you look at the example above you’ll see that a device with a width of exactly 768px will trigger both media queries, which may not be exactly what we want. So I added the ability to write inclusive and exclusive breakpoints to my list of requirements.

My (Eduardo Bouças’s) technique

This is my take on it.

Clean syntax, dynamic declaration

I’m a fan of Dmitry’s syntax, so my solution was inspired by it. However, I’d like some more flexibility in the way breakpoints are created. Instead of hardcoding the names of the breakpoints in the mixin, I used a multidimensional map to declare and label them.

$breakpoints: (phone: 640px, tablet: 768px, desktop: 1024px) !default; @include media(">phone", "<tablet") { } @include media(">tablet", "<950px") { }

The mixin comes with a set of default breakpoints, which you can override anywhere in the code by re-declaring the variable $breakpoints.

Inclusive and exclusive breakpoints

I wanted to have a finer control over the intervals in the expressions, so I included support for the less-than-or-equal-to and greater-than-or-equal-to operators. This way I can use the same breakpoint declaration in two mutually exclusive media queries.

@include media(">=phone", "<tablet") { } @include media(">=tablet", "<=950px") { } /* Compiles to */ @media (min-width: 640px) and (max-width: 767px) { } @media (min-width: 768px) and (max-width: 950px) { } Infer media types and handle logic disjunction

Similarly to the breakpoints, there’s a list for media types and other static expressions declared by default (which you can override by setting the variable $media-expressions). This adds support for optional media types, such as screen or handheld, but it’s also capable of correctly handling expressions with logical disjunctions, such as the retina media query we saw before. The disjunctions are declared as nested lists of strings.

$media-expressions: (screen: "screen", handheld: "handheld", retina2x: ("(-webkit-min-device-pixel-ratio: 2)", "(min-resolution: 192dpi)")) !default; @include media("screen", ">=tablet") { } @include media(">tablet", "<=desktop", "retina2x") { } /* Compiles to */ @media screen and (min-width: 768px) { } @media (min-width: 769px) and (max-width: 1024px) and (-webkit-min-device-pixel-ratio: 2), (min-width: 769px) and (max-width: 1024px) and (min-resolution: 192dpi) { }

There’s no rocket science under the hood, but the full implementation of the mixin isn’t something I could show in just a few lines of code. Instead of boring you with huge code snippets and neverending comments, I included a Pen with everything working and I’ll briefly describe the process it goes through to construct the media queries.

CodePen Embed Fallback How it works
  1. The mixin receives multiple arguments as strings and starts by going through each one to figure out if it represents a breakpoint, a custom width, or one of the static media expressions.
  2. If an operator is found, it is extracted and any matching breakpoint will be returned, or else we assume it’s a custom value and cast it to a number (using SassyCast).
  3. If it’s a static media expression, it checks for any or operators and generates all the combinations necessary to represent the disjunction.
  4. The process is repeated for all the arguments and the results will by glued together by the and connector to form the media query expression.

If you’d like to look at the complete Sass for it, it’s here. It’s called include-media on GitHub.

Final thoughts
  • I’m a big fan of this technique to make Sass talk to JavaScript. Because we declare breakpoints as a multidimensional list with their names as keys, exporting them in bulk to JavaScript becomes really straightforward and can be done automatically with just a few lines of code.
  • I’m not trying to put down other people’s solutions and I’m definitely not saying this one is better. I mentioned them to show some of the obstacles I found along the way to my ideal solution, as well as some great things they introduced that inspired my own solution.
  • You might have some concerns about the length and complexity of this implementation. While I understand, the idea behind it is that you download one single file, @import it into your project and start using it without having to touch the source code. Ping me on Twitter though if you have any questions.
  • You can get it from GitHub and you are very welcome to contribute with issues/code/love. I’m sure there’s still a lot we can do to make it better.
Update!

Eduardo made a website for his approach: @include-media.

Direct Link to ArticlePermalink

The post Nested Media Queries appeared first on CSS-Tricks.

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

Recreating Game Elements for the Web: The Among Us Card Swipe

Css Tricks - Tue, 02/09/2021 - 6:13am

As a web developer, I pay close attention to the design of video games. From the HUD in Overwatch to the catch screen in Pokemon Go to hunting in Oregon Trail, games often have interesting mechanics and satisfying interactions, many of which inspire my own coding games at Codepip.

Beyond that, implementing small slices of these game designs on a web stack is a fun, effective way to broaden your skills. By focusing on a specific element, your time is spent working on an interesting part without having to build out a whole game with everything that entails. And even in this limited scope, you often get exposed to new technologies and techniques that push on the boundaries of your dev knowledge.

As a case study for this idea, I’ll walk you through my recreation of the card swipe from Among Us. For anyone in the dark, Among Us is a popular multiplayer game. Aboard a spaceship, crewmates have to deduce who among them is an imposter. All the while, they complete mundane maintenance tasks and avoid being offed by the imposter.

The card swipe is the most infamous of the maintenance tasks. Despite being simple, so many players have struggled with it that it’s become the stuff of streams and memes.

Here’s my demo

This is my rendition of the card swipe task:

CodePen Embed Fallback

Next, I’ll walk you through some of the techniques I used to create this demo.

Swiping with mouse and touch events

After quickly wireframing the major components in code, I had to make the card draggable. In the game, when you start dragging the card, it follows your pointer’s position horizontally, but stays aligned with the card reader vertically. The card has a limit in how far past the reader it can be dragged to its left or right. Lastly, when you lift your mouse or finger, the card returns to its original position.

All of this is accomplished by assigning functions to mouse and touch events. Three functions are all that‘s needed to handle mouse down, mouse move, and mouse up (or touch start, touch move, and touch end if you‘re on a touchscreen device). Here’s the skeleton of that JavaScript code:

const card = document.getElementById('card'); const reader = document.getElementById('reader'); let active = false; let initialX; // set event handlers document.addEventListener('mousedown', dragStart); document.addEventListener('mousemove', drag); document.addEventListener('mouseup', dragEnd); document.addEventListener('touchstart', dragStart); document.addEventListener('touchmove', drag); document.addEventListener('touchend', dragEnd); function dragStart(e) { // continue only if drag started on card if (e.target !== card) return; // get initial pointer position if (e.type === 'touchstart') { initialX = e.touches[0].clientX; } else { initialX = e.clientX; } active = true; } function drag(e) { // continue only if drag started on card if (!active) return; e.preventDefault(); let x; // get current pointer position if (e.type === 'touchmove') { x = e.touches[0].clientX - initialX; } else { x = e.clientX - initialX; } // update card position setTranslate(x); } function dragEnd(e) { // continue only if drag started on card if (!active) return; e.preventDefault(); let x; // get final pointer position if (e.type === 'touchend') { x = e.touches[0].clientX - initialX; } else { x = e.clientX - initialX; } active = false; // reset card position setTranslate(0); } function setTranslate(x) { // don't let card move too far left or right if (x < 0) { x = 0; } else if (x > reader.offsetWidth) { x = reader.offsetWidth; } // set card position on center instead of left edge x -= (card.offsetWidth / 2); card.style.transform = 'translateX(' + x + 'px)'; } Setting status with performance.now()

Next, I had to determine whether the card swipe was valid or invalid. For it to be valid, you must drag the card across the reader at just the right speed. Didn’t drag it far enough? Invalid. Too fast? Invalid. Too slow? Invalid.

To find if the card has been swiped far enough, I checked the card’s position relative to the right edge of the card reader in the function dragEnd:

let status; // check if card wasn't swiped all the way if (x < reader.offsetWidth) { status = 'invalid'; } setStatus(status);

To measure the duration of the card swipe, I set start and end timestamps in dragStart and dragEnd respectively, using performance.now().

function setStatus(status) { // status is only set for incomplete swipes so far if (typeof status === 'undefined') { // timestamps taken at drag start and end using performance.now() let duration = timeEnd - timeStart; if (duration > 700) { status = 'slow'; } else if (duration < 400) { status = 'fast'; } else { status = 'valid'; } } // set [data-status] attribute on reader reader.dataset.status = status; }

Based on each condition, a different value is set on the reader’s data-status attribute. CSS is used to display the relevant message and illuminate either a red or green light.

#message:after { content: "Please swipe card"; } [data-status="invalid"] #message:after { content: "Bad read. Try again."; } [data-status="slow"] #message:after { content: "Too slow. Try again."; } [data-status="fast"] #message:after { content: "Too fast. Try again."; } [data-status="valid"] #message:after { content: "Accepted. Thank you."; } .red { background-color: #f52818; filter: saturate(0.6) brightness(0.7); } .green { background-color: #3dd022; filter: saturate(0.6) brightness(0.7); } [data-status="invalid"] .red, [data-status="slow"] .red, [data-status="fast"] .red, [data-status="valid"] .green { filter: none; } Final touches with fonts, animations, and audio

With the core functionality complete, I added a few more touches to get the project looking even more like Among Us.

First, I used a free custom font called DSEG to imitate the segmented type from old LCDs. All it took was hosting the files and declaring the font face in CSS.

@font-face { font-family: 'DSEG14Classic'; src: url('../fonts/DSEG14-Classic/DSEG14Classic-Regular.woff2') format('woff2'), url('../fonts/DSEG14-Classic/DSEG14Classic-Regular.woff') format('woff'), url('../fonts/DSEG14-Classic/DSEG14Classic-Regular.ttf') format('truetype'); }

Next, I copied the jitter animation of the text in the original. Game developers often add subtle animations to breath life into an element, like making a background drift or a character, well, breathe. To achieve the jitter, I defined a CSS animation:

@keyframes jitter { from { transform: translateX(0); } to { transform: translateX(5px); } }

At this point, the text glides smoothly back and forth. Instead, what I want is for it to jump back and forth five pixels at a time. Enter the steps() function:

#message { animation: jitter 3s infinite steps(2); }

Finally, I added the same audio feedback as used in Among Us.

let soundAccepted = new Audio('./audio/CardAccepted.mp3'); let soundDenied = new Audio('./audio/CardDenied.mp3'); if (status === 'valid') { soundAccepted.play(); } else { soundDenied.play(); }

Sound effects are often frowned upon in the web development world. A project like this an opportunity to run wild with audio.

And with that, the we’re done! Here’s that demo again:

CodePen Embed Fallback Try your own

Given how standardized the web has become in look and feel, this approach of pulling an element from a game and implementing it for the web is a good way to break out of your comfort zone and try something new.

Take this Among Us card swipe. In a small, simple demo, I tinkered with web fonts and animations in CSS. I monkeyed with input events and audio in JavaScript. I dabbled with an unconventional visual style.

Now it’s time for you to survey interesting mechanics from your favorite games and try your hand at replicating them. You might be surprised what you learn.

The post Recreating Game Elements for the Web: The Among Us Card Swipe appeared first on CSS-Tricks.

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

SVG within CSS

Css Tricks - Mon, 02/08/2021 - 11:07am

Stefan Judis has a “Today I Learned” (TIL) post explaining how SVGs filters can be inlined in CSS. The idea is that CSS has the filter property which supports some built-in functions, like grayscale(100%) and stuff like that.

But it can also point to a filter defined by SVG. So you could do filter: url(#my-custom-filter) which is in some inline <svg> as <filter id="my-custom-filter">. It’s kinda funny to have to refer out to the HTML like that. A filter is such a visual thing that it makes sense to bring it into the CSS. That looks like this:

img { filter: url('data:image/svg+xml,\ <svg xmlns="http://www.w3.org/2000/svg">\ <filter id="waves" x="-20%" y="-20%" width="140%" height="140%" filterUnits="objectBoundingBox" primitiveUnits="userSpaceOnUse" color-interpolation-filters="linearRGB">\ <feTurbulence type="turbulence" baseFrequency="0.01 0.01" numOctaves="1" seed="1" stitchTiles="noStitch" result="turbulence" />\ <feDisplacementMap in="SourceGraphic" in2="turbulence" scale="20" xChannelSelector="G" yChannelSelector="A" result="displacementMap" />\ </filter>\ </svg>#waves') ; }

That’s Stefan’s turbulence filter example, something CSS alone definitely cannot do.

Look at all those backslashes (\). Makes ya wish CSS had template literals, eh? Makes me nervous that a code formatter or minifier would choke on that, but I don’t actually know, maybe it would be fine.

What’s nice is that the SVG remains fairly intact (readable and editable). So here you can edit the SVG filter in the CSS and have a play:

CodePen Embed Fallback

I also think of Yoksel’s tools. This editor for two-tone and three-tone images is so cool. I can pick up one of those filters and drop it into some CSS as well:

CodePen Embed Fallback

Filters aren’t the only kind of SVG that makes some sense to inline into CSS though. You can put SVG drawing right into CSS as well.

CodePen Embed Fallback

This works everywhere but Safari in a quick blast through modern browsers. But I think in the not-so-distant past, we needed to encode more of the special characters in the SVG to get it to work (although you didn’t have to resort to base64). Yoskel’s URL-encoder is literally just for this — I just don’t know that it’s necessary anymore.

The post SVG within CSS appeared first on CSS-Tricks.

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

Animating a CSS Gradient Border

Css Tricks - Mon, 02/08/2021 - 5:24am

This little trick for gradient borders is super useful:

.border-gradient { border: 5px solid; border-image-slice: 1; border-image-source: linear-gradient(to left, #743ad5, #d53a9d); }

Here’s some basic demos from our article on the subject. Sephanie Eckles was sharing around the idea with more detail. Bramus Van Damme saw that and stretched it a bit by adding, then animating an angle to the gradient. Like:

div { --angle: 0deg; /* … */ border-image: linear-gradient(var(--angle), green, yellow) 1; animation: 10s rotate linear infinite; } @keyframes rotate { to { --angle: 360deg; } }

But wait! That’s not actually going to animate as-is. The browser doesn’t know that 360deg is an actual angle value, and not just some random string. If it did know it was an angle value, it could animate it. So, tell it:

@property --angle { syntax: '<angle>'; initial-value: 0deg; inherits: false; }

See Bramus’ article for the demos there. Bonafide CSS trick. I can’t wait for more support for @property (Chrome only, as I write), because it really unlocks some cool CSS trickery. Animating numbers visually, for example.

Direct Link to ArticlePermalink

The post Animating a CSS Gradient Border appeared first on CSS-Tricks.

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

(Jay Freestone’s) Front-end predictions for 2021

Css Tricks - Mon, 02/08/2021 - 5:24am

React framework maturity, early container queries, WASM adoption, and monoliths. I’ll take all four, please. Not feeling like a particularly front-end-y? Jay says:

Interestingly, the biggest developments in the front-end are unlikely to be traditionally front-end concerns. Back in our 2019 forecast, we noted that the role of the front-end developer was increasingly shifting towards ‘full-stack’, and this has borne out to be true. Even the evolution of our frameworks and tools suggests this, with an increased focus on data-fetching, concurrency, security and scalability.

If I’m allowed to predict, and thus manifest, improvements in the web platform in 2021, I’d like to predict HTML’s inert attribute shipping without a flag in all three browser engines.

Direct Link to ArticlePermalink

The post (Jay Freestone’s) Front-end predictions for 2021 appeared first on CSS-Tricks.

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

Exploring the Complexities of Width and Height in CSS

Css Tricks - Fri, 02/05/2021 - 12:51pm

The following article is co-authored by Uri Shaked and Michal Porag.

Let’s explore the complexities of how CSS computes the width and height dimensions of elements. This is based on countless late-night hours debugging and fiddling with lots of combinations of CSS properties, reading though the specs, and trying to figure out why some things seem to behave one way or another.

But before jumping in, let’s cover some basics so we’re all on the same page.

The basics

You have an element, and you want it to be 640px wide and 360px tall. These are just arbitrary numbers that conform to 16:9 pixel ratio. You can set them explicitly like this:

.element { width: 640px; height: 360px; }

Now, the design calls for some padding inside that element. So you modify the CSS:

.element { width: 640px; height: 360px; padding: 10px; }

What is the rendered width and height of the element now? I bet you can guess… it’s not 640×360px anymore! It’s actually 660×380px, because the padding adds 10px to each side (i.e. top, right, bottom and left), for an additional 20px on both the height and width.

This has to do with the box-sizing property: if it’s set to content-box (the default value), the rendered size of the element is the width and height plus the padding and border. That might mean that the rendered size is bigger than we intend which is funny because it might wind up that an element’s declared width and height values are completely different than what’s rendered.

That’s the power of The CSS Box Model. It calculates width and height like so:

/* Width */ width + padding-left + padding-right + border-left + border-right /* Height */ height + padding-top + padding-bottom + border-top + border-bottom

What we just saw is how the dimensions for a block element are computed. Block elements include any element that naturally takes up the full width that’s available. So, by nature, it doesn’t matter how much content the element contains because its width is always 100%, that is, until we alter it. Think of elements like <p>, <article>, <main>, <div>, and so many more.

But now we ought to look at inline elements because they behave differently when it comes to The Box Model and how their dimensions are computed. After that, we’ll look at the relationship between parent and child elements, and how they affect the width and height computations of each other.

The curious case of inline elements

As we just saw, the padding and border of any element are both included in the element’s computed width and height dimensions. Funny enough, there are cases where the width and height properties have no effect whatsoever. Such is the case when working with inline elements.

An inline element is an element that’s width and height are determined by the content it contains. Inline elements, such as a <span>, will completely ignore the width and height as well the the top and bottom margin properties because, well, the content is what determines the dimensions. Here, sometimes a visual can help.

CodePen Embed Fallback

Just look at how nesting a block element inside of an inline element breaks the inline element’s shape simply because the block element is not defined by the amount of content it contains, but rather the amount of available space. You can really see that in action when we add a border to the inline element. Look how the inline element abruptly stops where the paragraph comes in, then continues after the paragraph.

CodePen Embed Fallback

The span sees the paragraph, which interrupts the inline flow of the span and essentially breaks out of it. Fascinating stuff!

But there’s more! Look how the inline element completely overlooks width and margin, even when those are declared right on it.

CodePen Embed Fallback

Crazy!

Parent and child elements

The parent-child relationship is a common pattern. A parent element is one that contains other elements nested inside it. And those nested elements are the parent element’s children.

<!-- The parent element --> <div class="parent"> <!-- The children --> <div class="child"></div> <div class="another-child"></div> <div class="twins">Whoa!</div> </div>

The width and height of an element gets super interesting with parent and child elements. Let’s look at all the interesting quirks we get with this.

Relative units

Let’s start with relative units. A relative unit is computed by its context, or relation to other elements. Yeah, that’s sort of a convoluted definition. There are several different types of relative units, but let’s take percentages as an example. We can say that an element is 100% wide.

<div class="child"> <!-- nothing yet --> </div> .parent { width: 100%; }

Cool. If we plop that element onto an empty page, it will take up 100% of the available horizontal space. And what that 100% computes to depends on the width of the browser, right? 100% of a browser that’s 1,500 pixels is 1,500 pixels wide. 100% of a browser that’s 500 pixels is 500 pixels wide. That’s what we mean by a relative unit. The actual computed value is determined by the context in which it’s used.

So, the astute reader may already be thinking: Hey, so that’s sort of like a child element that’s set to a parent element’s width. And that would be correct. The width of the child at 100% will compute based on the actual width of the parent element that contains it.

Height works much the same way: it’s relative to the parent’s height. For example, two parent elements with different height dimensions but identical children result in children with different heights.

CodePen Embed Fallback

Padding and margin

The width and height of parent-child combinations get even more interesting when we look at other properties, such as padding and margin. Apparently, when we specify a percentage value for padding or margin, it is always relative to the width of the parent, even when dealing with vertical edges.

Some clever designers have taken advantage of it to create boxes of equal width and height, or boxes that keep a certain aspect ratio when the page resizes. This is particularly useful for video or image content, but can also be (ab)used in creative ways. Go ahead, type whatever you want into the editable element in this demo. The box maintains a proportional height and width, no matter how much (or little) content is added.

CodePen Embed Fallback

This technique for creating aspect ratio boxes is lovingly referred to as the “padding hack.” Chris has covered it extensively. But now that we have the aspect-ratio property gaining wide browser support, there’s less reason to reach for it.

display: inline and inline-block

Now that we’ve taken looks at how parent and child element dimensions are computed, we should check out two other interesting property values that affect an element’s width: min-content and max-content.

These properties tell the browser to look at the content of the element in order to determine its width. For instance, if we have the text: “hello CSS encyclopedia, nice to meet you!”, the browser would calculate the space that text would take up on the screen, and use it as the width.

The difference between min-content and max-content lies in how the browser does this calculation. For max-content, the browser pretends it has infinite space, and lays all the text in a single line while measuring its width.

For min-content, the browser pretends it has zero space, so it puts every word / child inline element in a different line. Let’s see this in action:

CodePen Embed Fallback CodePen Embed Fallback

We actually saw max-content in action when we looked at the difference between block and inline elements. Inline elements, remember, are only as wide and tall as the content they contain. We can make most elements inline elements just by declaring display: inline; on it.

CodePen Embed Fallback

Cool. Another weapon we have is display: inline-block;. That creates an inline element, but enhanced with block-level computations in The Box Model. In other words, it’s an inline element that respects margin, width and height. The best of both worlds!

CodePen Embed Fallback Cyclic percentage size

Did that last point make sense? Well, hopefully I won’t confuse you with this:

CodePen Embed Fallback

The child element in this example has a relative width of 33%. The parent element does not have a width declared on it. How the heck is the child’s computed width get calculated when there’s nothing relative to it?

To answer that, we have to look at how the browser calculates the size of the elements in this example. We haven’t defined a specific width for the parent element, so the browser uses the initial value for width , which is auto. And since the parent element’s display is set to inline-block, auto behaves like max-content. And max-content, as we saw, should mean the parent element is as wide as the content in it, which is everything inside the child element.

So, the browser looks at the element’s content (children) to determine its width. However, the width of the child also depends on the parent’s width! Gah, this is weird!

The CSS Box Sizing Module specification calls this cyclic percentage sizing. I’m not sure why it’s called that exactly, but it details the complex math the browser has to do to (1) determine the parent element’s width, and (2) reconcile that width to the relative width of the child.

The process is actually pretty cool once you get over the math stuff. The browser starts by calculating a temporary width for the child before its declared value is applied. The temporary width the browser uses for the child is auto which we saw behaves like max-content which, in turn, tells the browser that the child needs to be as wide as the content it contains. And right now, that’s not the declared 33% value.

That max-content value is what the browser uses to calculate the parent’s width. The parent, you see, needs to be at least as wide as the content that it contains, which is everything in the child at max-content. Once that resolves, the browser goes back to the child element and applies the 33% value that’s declared in the CSS.

This is how it looks:

There! Now we know how a child element can contribute to the computed value of its parent.

M&Ms: the min- and max- properties

Hey, so you’re probably aware that the following properties exist:

  • min-width
  • min-height
  • max-width
  • max-height

Well, those have a lot to do with an element’s width and height as well. They specify the limits an element’s size. It’s like saying, Hey, browser, make sure this element is never under this width/height or above this width/height.

So, even if we have declared an explicit width on an element, say 100%, we can still cap that value by giving it a max-width:

element { width: 100%; max-width: 800px; }

This allows the browser to let the element take up as much space as it wants, up to 800 pixels. Let’s look what happens if we flip those values around and set the max-width to 100% and width to 800px:

element { width: 800px; max-width: 100%; }

Hey look, it seems to result in the exact same behavior! The element takes up all the space it needs until it gets to 800 pixels.

CodePen Embed Fallback

Apparently, things start to get more complex as soon as we add a parent element into the mix. This is the same example as above, with one notable change: now each element is a child of an inline-block element. Suddenly, we see a striking difference between the two examples:

CodePen Embed Fallback

Why the difference? To understand, let’s consider how the browser calculates the width of the elements in this example.

We start with the parent element (.parent). It has a display property set to inline-block, and we didn’t specify a width value for it. Just like before, the browser looks at the size of its children to determine its width. Each box in this example is wrapped in the .parent element.

The first box (#container1) has a percentage width value of 100%. The width of the parent resolves to the width of the text within (the child’s max-content), limited by the value we specified by max-width, and that is used to calculate the width of the child as well.

The second box (#container2) has a set width of 800px, so its parent width is also 800px — just wide enough to fit its child. Then, the child’s max-width is resolved relative to the parent’s final width, that is 800px. So both the parent and the child are 800px wide in this case.

So, even though we initially saw the two boxes behave the same when we swapped width and max-width values, we now know that isn’t always true. In this case, introducing a parent element set to display: inline-block; threw it all off!

Adding min(), max() and clamp() into the mix

The min(), max() and clamp() are three useful CSS functions that let us define the size of elements responsively… without media queries!

  • min(): Returns the minimum value of its arguments. The arguments can be given in different units, and we can even mix and match absolute and relative units, like min(800px, 100%).
  • max(): Returns the maximum value of its arguments. Just like min(), you can mix and match different units.
  • clamp(): A shorthand function for doing min and max at once: clamp(MIN, VAL, MAX) is resolved as max(MIN, min(VAL, MAX)). In other words, it will return VAL, unless it exceeds the boundaries defined by MIN and MAX, in which case it’ll return the corresponding boundary value.

Like this. Check out how we can effectively “re-write” the max-width example from above using a single CSS property:

.element { width: min(800px, 100%); } /* ...is equivalent to: */ .element { width: 800px; max-width: 100%; }

That would set the width of the element to 800px, but make sure we don’t exceed the width of the parent (100%). Just like before, if we wrap the element with an inline-block parent, we can observe it behaving differently than the max-width variation:

CodePen Embed Fallback

The width of the children (800px) is the same. However, if you enlarge the screen (or use CodePen’s 0.5x button to zoom out), you will notice that the second parent is actually larger.

It boils down to how the browser calculates the parent’s width: we didn’t specify a width for the parent, and as child’s width value is using relative units, the browser ignores it while calculating the parent’s width and uses the max-content child of the child, dictated by the “very long … long” text.

Wrapping up

Phew! It’s crazy that something as seemingly simple as width and height actually have a lot going on. Sure, we can set explicit width and height values on an element, but the actual values that render often end up being something completely different.

That’s the beauty (and, frankly, the frustration) with CSS. It’s so carefully considered and accounts for so many edge cases. I mean, the concept of The Box Model itself is wonderfully complex and elegant at the same time. Where else can we explicitly declare something in code and have it interpreted in different ways? The width isn’t always the width.

And we haven’t even touched on some other contributing factors to an element’s dimensions. Modern layout techniques, like CSS Flexbox and Grid introduce axes and track lines that also determine the rendered size of an element.

Authors: Uri Shaked and Michal Porag

The post Exploring the Complexities of Width and Height in CSS appeared first on CSS-Tricks.

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

Syndicate content
©2003 - Present Akamai Design & Development.