Developer News

The failed promise of Web Components

Css Tricks - Mon, 10/19/2020 - 12:21pm

Lea has some words:

Perusing the components on fills me with anxiety, and I’m perfectly comfortable writing JS — I write JS for a living! What hope do those who can’t write JS have? Using a custom element from the directory often needs to be preceded by a ritual of npm flugelhorn, import clownshoes, build quux, all completely unapologetically because “here is my truckload of dependencies, yeah, what”. Many steps are even omitted, likely because they are “obvious”.

When I wrote A Bit on Web Component Libraries, I was told the main thing I got wrong is that:

The idea was to make primitives that libraries could build on top of so they could ship less code. It was always the intention that you would use a library with them.

It was many years ago that HTML imports died. It was Dave’s pet peeve about Web Components for a long time. So I guess after that, it was a all-JavaScript-or-bust approach for Web Components. And I hate to say it, but it feels like it’s a lot closer to a bust than a boon.

I’m still optimistic though. Web Components can do some very cool stuff that only Web Components can do. The Shadow DOM being a big part of that. For example, I remember years ago Twitter experimented with making embedded Tweets into Web Components (instead of iframes) because it was way faster (in every way). That never manifested (🤷‍♂️), but it seemed like a damn fine idea to me.

I think the styling story is a big deal. I bet I’d reach for them at least slightly more if styling them wasn’t so weird. I saw Scott was asking about it just today and 75% of people wish there was a way to just reach into that Shadow DOM and style it from regular CSS. I get why that needs to be protected (that’s a huge point of the Shadow DOM in the first place), but having to very explicitly reach in seems like enough protection to me.

Direct Link to ArticlePermalink

The post The failed promise of Web Components appeared first on CSS-Tricks.

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

Our Best Posts on Web Components

Css Tricks - Mon, 10/19/2020 - 11:56am
Article Mar 18, 2019 An Introduction to Web Components Author Caleb Williams Article Mar 19, 2019 Crafting Reusable HTML Templates Author Caleb Williams Article Mar 22, 2019 Advanced Tooling for Web Components Author Caleb Williams Article Mar 20, 2019 Creating a Custom Element from Scratch Author Caleb Williams Article Jan 8, 2019 Styling a Web Component Author Chris Coyier Article Mar 21, 2019 Encapsulating Style and Structure with Shadow DOM Author Caleb Williams Article Jul 21, 2020 What ya need there is a bit of templating Author Chris Coyier Article Dec 27, 2017 ::part and ::theme, an ::explainer Author Robin Rendle Article Jul 28, 2020 A Bit on Web Component Libraries Author Chris Coyier Article Jul 20, 2017 Playing with Shadow DOM Author Chris Coyier Article Jun 9, 2017 An intro to web components with otters Author Chris Coyier Article Sep 7, 2018 Shadow DOM in Ionic Author Chris Coyier

A bit of backstory on why this page exists…

I made a fancy new Gutenberg block to insert posts into other posts, so this page is an example of using that (heavily) make a meta blog post about other blog posts. For the most part, topical pages like this are best served by tag pages. For example, our tag page for Web Components has more posts and is sortable in ways this is not. This is just a way to make a curated and hand-sorted grouping of posts, which is something we’ve done for a while with “Guide Collections”. But, we’re spinning down Guide Collections and redirecting them to tag pages and pages like this because they are easier to maintain.

The post Our Best Posts on Web Components appeared first on CSS-Tricks.

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

Comparing Styling Methods in 2020

Css Tricks - Mon, 10/19/2020 - 10:36am

Over on Smashing, Adebiyi Adedotun Lukman covers all these styling methods. It’s in the context of Next.js, which is somewhat important as Next.js has some specific ways you work with these tools, is React and, thus, is a components-based architecture. But the styling methods talked about transcend Next.js, and can apply broadly to lots of websites.

Here are my hot takes on the whole table-of-contents of styling possibilities these days.

  • Regular CSS. If you can, do. No build tooling is refreshing. It will age well. The only thing I really miss without any other tooling is nesting media queries within selector blocks.
  • Sass. Sass has been around the block and is still a hugely popular CSS preprocessor. Sass is built into tons of other tools, so choosing Sass doesn’t always mean the same thing. A simple Sass integration might be as easy as a sass --watch src/style.scss dist/style.css npm script. Then, once you’ve come to terms with the fact that you have a build process, you can start concatenating files, minifying, busting cache, and all this stuff that you’re probably going to end up doing somehow anyway.
  • Less & Stylus. I’m surprised they aren’t more popular since they’ve always been Node and work great with the proliferation of Node-powered build processes. Not to mention they are nice feature-rich preprocessors. I have nothing against either, but Sass is more ubiquitous, more actively developed, and canonical Sass now works fine in Node-land,
  • PostCSS. I’m not compelled by PostCSS because I don’t love having to cobble together the processing features that I want. That also has the bad side effect of making the process of writing CSS different across projects. Plus, I don’t like the idea of preprocessing away modern features, some of which can’t really be preprocessed (e.g. custom properties cannot be preprocessed). But I did love Autoprefixer when we really needed that, which is built on PostCSS.
  • CSS Modules. (Built on PostCSS). If you’re working with components in any technology, CSS modules give you the ability to scope CSS to that component, which is an incredibly great idea. I like this approach wherever I can get it. Your module CSS can be Sass too, so we can get the best of both worlds there.
  • CSS-in-JS. Let’s be real, this means “CSS-in-React.” If you’re writing Vue, you’re writing styles the way Vue helps you do it. Same with Svelte. Same with Angular. React is the un-opinionated one, leaving you to choose between things like styled-components, styled-jsx, Emotion… there are a lot of them. I have projects in React and I just use Sass+CSS Modules and think that’s good but a lot of people like CSS-in-JS approaches too. I get it. You get the scoping automatically and can do fancy stuff like incorporate props into styling decisions. Could be awesome for a design system.
  • All-in on utility styles: Big advantages: small CSS files, consistent yet flexible styles. Big disadvantage: you’ve got a zillion classes all commingled in your markup, making it cumbersome to read and refactor. I’m not compelled by it, but I get it, those advantages really hit for some folks.

If you want to hear some other hot takes on this spectrum, the Syntax FM fellas sounded off on this recently.

The post Comparing Styling Methods in 2020 appeared first on CSS-Tricks.

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

Focus management and inert

Css Tricks - Mon, 10/19/2020 - 3:56am

Many forms of assistive technology use keyboard navigation to understand and take action on screen content. One way of navigating is via the Tab key. You may already be familiar with this way of navigating if you use it to quickly jump from input to input on a form without having to reach for your mouse or trackpad.

Tab will jump to interactive elements in the order they show up in the DOM. This is one of the reasons why it is so important that the order of your source code matches the visual hierarchy of your design.

The list of interactive elements that are tabbable is:

An interactive element gains focus when:

  • It has been navigated to via the Tab key, 
  • it is clicked on, following an anchor that links to another focusable element,
  • or focus is programmatically set through element.focus() in JavaScript.

Focus is analogous to hovering over an element with your mouse cursor, in that you’re identifying the thing you want to activate. It’s also why visually obvious focus styles are so important.

Focus indication moving through a homepage wireframe. It starts on the logo, moves to products, then services, then careers, blog, contact, and stops on a Learn more button. Focus management

Focus management is the practice of coordinating what can and cannot receive focus events. It is one of the trickier things to do in front-end development, but it is important for making websites and web apps accessible.

Good practices for focus management

99% of the time, you want to leave focus order alone. I cannot stress this enough. 

Focus will just work for you with no additional effort required, provided you’re using the <button> element for buttons, the anchor element for links, the <input> element for user input, etc.

There are rare cases where you might want to apply focus to something out of focus order, or make something that typically can’t receive focus events be focusable. Here are some guidelines for how to go about it in an accessible, intuitive to navigate way:

Do: learn about the tabindex attribute

tabindex allows an element to be focused. It accepts an integer as a value. Its behavior changes depending on what integer is used.

Don’t: Apply tabindex="0" to things that don’t need it

Interactive elements  that can receive keyboard focus (such as the <button> element) don’t need to have the tabindex attribute applied to them.  

Additionally, you don’t need to declare tabindex on non-interactive elements to ensure that they can be read by assistive technology (in fact, this is a WCAG failure if no role and accessible name is present). Doing so actually creates an unexpected and difficult to navigate experience for a person who uses assistive technology — they have other, expected ways to read this content.

✅ Do: Use tabindex="-1" for focusing with JavaScript

tabindex="-1" is used to create accessible interactive widgets with JavaScript.

A declaration of tabindex="-1" will make an element focusable via JavaScript or click/tap. It will not, however, let it be navigated to via the Tab key.

❌ Don’t: Use a positive integer as a tabindex value

This is a serious antipattern. Using a positive integer will override the expected tab order, and create a confusing and disorienting experience for the person trying to navigate your content. 

One instance of this is bad enough. Multiple declarations is a total nightmare. Seriously: don’t do it.

❌ Don’t: Create a manual focus order

Interactive elements can be tabbed to just by virtue of being used. You don’t need to set a series of tabindex attributes with incrementing values on every interactive element in the order you think the person navigating your site should use. You’ll let the order of the elements in the DOM do this for you instead.

Focus trapping

There may be times where you need to prevent things from being focused. A good example of this is focus trapping, which is the act of conditionally restricting focus events to an element and its children.

Focus trapping is not to be confused with keyboard traps (sometimes referred to as focus traps). Keyboard traps are situations where someone navigating via keyboard cannot escape out of a widget or component because of a nasty loop of poorly-written logic.

A practical example of what you would use focus trapping for would be for a modal:

Focus indication moving through a homepage wireframe and opening a modal to demonstrate focus trapping. Inside the modal are tab stops for the modal container, a video play button, a cancel button, a purchase button, and a close button. After the modal is closed focus is returned to the button that triggered the modal. Why is it important?

Keeping focus within a modal communicates its bounds, and helps inform what is and is not modal content — it is analogous to how a sighted person can see how a modal “floats” over other website or web app content. This is important information if: 

  • You have low or no vision and rely on screen reader announcements to help communicate the shift in interaction mode.
  • You have low vision and a magnified display, where focusing outside of the bounds of the modal may be confusing and disorienting.
  • You navigate solely via keyboard and could otherwise tab out of the modal and get lost on the underlying page or view trying to get back into the modal.
How do you do it?

Reliably managing focus is a complicated affair. You need to use JavaScript to:

  1. Determine the container elements of all focusable elements on the current page or view.
  2. Identify the bounds of the trapped content, including the first and last focusable item.
  3. Remove both interactivity and discoverability from anything identified as focusable that isn’t within that set of trapped content.
  4. Move focus into the trapped content.
  5. Listen for events that signals dismissing the trapped content (save, cancel, dismissal/hitting the Esc key, etc.).
  6. Dismiss the trapped content area when triggered by a pertinent event.
  7. Restore previously removed interactivity. 
  8. Move focus back to the interactive element that triggered the trapped content. 
Why do we do it?

I’m not going to lie: this is all tricky and time-consuming to do. However, focus management and a sensible, usable focus order is a Web Content Accessibility Guideline. It’s important enough that it’s considered part of an international, legally-binding standard about usability.

Tabbable and discoverable

There’s a bit of a trick to removing both discoverability and interactivity. 

Screen readers have an interaction mode that allows them to explore the page or view via a virtual cursor. The virtual cursor also lets the person using the screen reader discover non-interactive parts of the page (headings, lists, etc.). Unlike using Tab and focus styles, the virtual cursor is only available to people using a screen reader.

When you are managing focus, you may want to restrict the ability for the virtual cursor to discover content. For our modal example, this means preventing someone from accidentally “breaking out” of the bounds of the modal when they’re reading it.

Discoverability can be suppressed via a judicious application of aria-hidden="true". However, interactivity is a little more nuanced.

Enter inert

The inert attribute is a global HTML attribute that would make removing, then restoring the ability of interactive elements to be discovered and focused a lot easier. Here’s an example of how it would work:

<body>   <div      aria-labelledby="modal-title"     class="c-modal"      id="modal"      role="dialog"      tabindex="-1">     <div role="document">       <h2 id="modal-title">Save changes?</h2>       <p>The changes you have made will be lost if you do not save them.<p>       <button type="button">Save</button>       <button type="button">Discard</button>     </div>   </div>   <main inert>     <!-- ... -->   </main> </body>

I am deliberately avoiding using the <dialog> element for the modal due to its many assistive technology support issues.

inert has been declared on the <main> element following a save confirmation modal. What this means that all content contained within <main> cannot receive focus nor be clicked. 

Focus is restricted to inside of the modal. When the modal is dismissed, inert can be removed from the <main> element. This way of handling focus trapping is far easier compared to existing techniques.

Remember: A dismissal event can be caused by the two buttons inside our modal example, but also by pressing Esc on your keyboard. Some modals also let you click outside of the modal area to dismiss, as well.

Support for inert

The latest versions of Edge, Chrome, and Opera all support inert when experimental web platform features are enabled. Firefox support will also be landing soon! The one outlier is both desktop and mobile versions of Safari.

I’d love to see Apple implement native support for inert. While a polyfill is available, it has non-trivial support issues for all the major screen readers. Not great! 

In addition, I’d like to call attention to this note from the inert polyfill project’s README:

The polyfill will be expensive, performance-wise, compared to a native inert implementation, because it requires a fair amount of tree-walking. 

Tree-walking means the JavaScript in the polyfill will potentially require a lot of computational power to work, and therefore slow down the end-user experience. 

For lower power devices, such as budget Android smartphones, older laptops, and more powerful devices doing computationally-intensive tasks (such as running multiple Electron apps), this might mean freezing or crashing occurs. Native browser support means this sort of behavior is a lot less taxing on the device, as it has access to parts of the browser that JavaScript doesn’t. 


Personally, I am disappointed by Apple’s lack of support for inert. While I understand that adding new features to a browser is incredibly complicated and difficult work, inert seems like a feature Apple would have supported much earlier.

macOS and iOS have historically had great support for accessibility, and assistive technology-friendly features are a common part of their marketing campaigns. Supporting inert seems like a natural extension of Apple’s mission, as the feature itself would do a ton for making accessible web experiences easier to develop.

Frustratingly, Apple is also tight-lipped about what it is working on, and when we can generally expect to see it. Because of this, the future of inert is an open question.


Igalia is a company that works on browser features. They currently have an experiment where the public can vote on what features they’d like to see. The reasoning for this initiative is outside the scope of this article, but you can read more about it on Smashing Magazine.

One feature Igalia is considering is adding WebKit support for inert. If you have been looking for a way to help improve accessibility on the web, but have been unsure of how to start, I encourage you to pledge. $5, $10, $25. It doesn’t have to be a huge amount, every little bit adds up.

Pledge Now Wrapping up

Managing focus requires some skill and care, but is very much worth doing. The inert attribute can go a long way to making this easier to do.

Technologies like inert also represents one of the greatest strengths of the web platform: the ability to pave the cowpaths of emergent behavior and codify it into something easy and effective.

Further reading

Thank you to Adrian Roselli and Sarah Higley for their feedback.

The post Focus management and inert appeared first on CSS-Tricks.

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

The :focus-visible Trick

Css Tricks - Fri, 10/16/2020 - 9:12am

Always worth repeating: all interactive elements should have a focus style. That way, a keyboard user can tell when they have moved focus to that element.

But if you use :focus alone for this, it has a side effect that a lot of people don’t like. It means that when you click (with a mouse) on an interactive element, you’ll see the focus style. Arguably, you don’t need that feedback as a mouse user, because you just moved your cursor there and clicked. Whatever you think of that, it’s annoyed so many people over the years that they remove focus styles entirely, which is a gnarly net loss for accessibility on the web.

What if we could apply focus styles only when the keyboard is used to focus something, not the mouse? Lea Verou put a finger on this a few years back:

I’m gonna start blanket adding the following rule to all my stylesheets:

:focus:not(:focus-visible) { outline: none }

Gets rid of the annoying outline for mouse users but preserves it for keyboard users, and is ignored by browsers that don’t support :focus-visible.

— Lea Verou (@LeaVerou) September 28, 2018

That was in response to Chrome dropping the feature behind a flag. Clever clever.

Fast forward a couple of years, Chrome is releasing it without a flag. They are on board with Lea’s idea:

By combining :focus-visible with :focus you can take things a step further and provide different focus styles depending on the user’s input device. This can be helpful if you want the focus indicator to depend on the precision of the input device:

/* Focusing the button with a keyboard will show a dashed black line. */ button:focus-visible { outline: 4px dashed black; } /* Focusing the button with a mouse, touch, or stylus will show a subtle drop shadow. */ button:focus:not(:focus-visible) { outline: none; box-shadow: 1px 1px 5px rgba(1, 1, 0, .7); }

I might suggest trying those selectors without the button, making them globally applied!

There is more to dig into, so I’ll link up some more stuff here:

  • The Chromium Blog post covers the heuristics of the selector. It’s tricky. It’s like there is an algorithm to determine if :focus-visible is going to match or not, which you just largely need to trust. It also covers the idea that Firefox has long had :-moz-focusring, but the behavior is different enough that they don’t recommend using it if you’re shooting for consistent behavior.
  • Matthias Ott blogged about it with some good info, like using the official polyfill and how to look at the styles properly in DevTools (there is a new checkbox for it).
  • We’ve covered this before. In that, we noted Lea’s tweet that she thought usage would explode when it ships for real. Let’s see (and hope)!
  • Our almanac entry has a bunch of details.

The post The :focus-visible Trick appeared first on CSS-Tricks.

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

People Problems

Css Tricks - Fri, 10/16/2020 - 4:45am

Just the other day, Jeremy Keith wrote that problems with performance work isn’t only a matter of optimization and fixing code, but also tackling people problems:

It struck me that there’s a continuum of performance challenges. On one end of the continuum, you’ve got technical issues. These can be solved with technical solutions. On the other end of the continuum, you’ve got human issues. These can be solved with discussions, agreement, empathy, and conversations (often dreaded or awkward).

I think that, as developers, we tend to gravitate towards the technical issues. That’s our safe space. But I suspect that bigger gains can be reaped by tackling the uncomfortable human issues.

This was definitely shocking to learn when I joined a company a few years ago and found that there was a mountain of performance work that I couldn’t do alone. I started trying to teach folks about performance, as well as holding office hours and hopping onto projects and teams that needed help. But I realized that all this work didn’t help. The website I was working on in my spare time was getting slower, despite my best efforts.

Frustrated and exhausted, one day I sat back in my chair and realized that I couldn’t do all this work alone. The real problem was this: there’s no incentive for folks to care. If performance magically improved by ten thousand percent, no one in the company would have noticed. Customers would have noticed, but we all probably wouldn’t have. Except me, because I’m a nerd.

In Ethan Marcotte’s latest talk, he describes this people problem when it comes to design systems:

Creating modular components isn’t the primary goal or even the primary benefit of creating a design system. And what’s more, a focus on process and people always leads to more sustainable systems.

Design systems are about good, quality front-end code just like performance is, too. But if people within an organization are not incentivized to use the components within a library or talk to the design systems team, then that’s where things quickly get bonkers.

I’d maybe simplify this people problem a bit: the codebase is easy to change, but the incentives within a company are not. And yet it’s the incentives that drive what kind of code gets written — what is acceptable, what needs to get fixed, how people work together. In short, we cannot be expected to fix the code without fixing the organization, too.

The most obvious incentives are money and performance ratings, or even hiring a person or team dedicated to this particular line of work. Improving visibility into performance problems and celebrating big wins is another thing that can be done to shift the balance and make folks care more about this whole new area of expertise. But these things really have to come from the top down; not from the the bottom up. At least that’s been true in my experience.

My point here is that there’s no single solution to fix the incentive problem in large organizations. It sounds silly, but in order to make that website, the biggest hurdles to overcome are those incentives. If no one cares about performance work today, then shouting and screaming and being a jerk about it won’t help at all.

Trust me, I have been that jerk.

The post People Problems appeared first on CSS-Tricks.

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

Full Bleed

Css Tricks - Thu, 10/15/2020 - 10:52am

We’ve covered techniques before for when you want a full-width element within a constrained-width column, like an edge-to-edge image within a narrower column of text. There are loads of techniques.

Perhaps my favorite is this little utility class:

.full-width { width: 100vw; position: relative; left: 50%; right: 50%; margin-left: -50vw; margin-right: -50vw; }

That works as long as the column is centered and you don’t mind having to hide overflow-x on the column (or the body) as this can trigger horizontal overflow otherwise.

There was a little back and forth on some other ideas lately…

Josh Comeau blogged that you could set up a three-column grid, and mostly place content in the middle column, but then have the opportunity to bust out of it:

.wrapper { display: grid; grid-template-columns: 1fr min(65ch, 100%) 1fr; } .wrapper > * { grid-column: 2; } .full-bleed { width: 100%; grid-column: 1 / -1; }

I think this is clever. I’d probably use it. But I admit there are bits that feel weird to me. For instance…

  • Now everything within the container is a grid element. Not a huge deal, but the elements will behave slightly differently. No margin collapsing, for one.
  • You have to apply the default behavior you want to every single element. Rather than elements naturally stacking on top of each other, you have to select them and tell them where to go and let them stack themselves. Feels a little less like just going with the web’s grain. Then you still need a utility class to do the full bleed behavior.

What I really like about the idea is that it gives you this literal grid to work with. For example, your left spacer could be half the width of the right and that’s totally fine. It’s setting up that space to be potentially used, like Ethan talked about in his article on constrained grids.

Kilian Valkhof responded to the article with this idea:

body > *:not(img):not(video) { position: relative; max-width: 40rem; margin: auto; }

Also very clever. This constrains the width of everything (in whatever container, and it wouldn’t have to be the body) except the elements you want to bust out (which could be a utility class there too, and not necessarily images and videos).

Again, to me, this feeling that I have to select every single element and provide it this fundamental information about layout feels slightly weird. Not like “don’t use it” weird, just not something I’m used to doing. Historically, I’m more comfortable sizing and positioning a container and letting the content in that container lay itself out without much further instruction.

You know what I like the most? That we have so many powerful layout tools in CSS and we have conversations about the pros and cons of pulling off exactly what we’re going for.

Article Feb 6, 2020 Full-Width Elements By Using Edge-to-Edge Grid Author Chris Coyier Article May 25, 2011 Creating a Body Border Author Chris Coyier Article Mar 5, 2015 Creating responsive, touch-friendly carousels with Flickity Author David DeSandro Article May 16, 2011 Full Browser Width Bars Author Chris Coyier Article Jul 25, 2016 Full Width Containers in Limited Width Parents Author Chris Coyier Article Jul 20, 2020 When do you use inline-block? Author Chris Coyier

The post Full Bleed appeared first on CSS-Tricks.

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

Layoutit Grid: Learning CSS Grid Visually With a Generator

Css Tricks - Thu, 10/15/2020 - 4:48am

Layoutit Grid is an interactive open source CSS Grid generator. It lets you draw your designs and see the code as you go. You can interact with the code, add or remove track lines and drag them around to change the sizing — and you get to see the CSS and HTML change in real time!

Add some tracks and see how they’re made in CSS

When you are done with a layout, you can create a CodePen or grab the code to jumpstart your next project. The tool brings the code to the forefront, helping you learn CSS grid as you work directly with it.

CSS Grid is a whole new way of thinking about layouts

We can now create robust responsive layouts for our web experiences. We can finally learn to design with a coherent set of layout tools instead of memorizing piles of hacks to force elements into position.

Now, I’m not saying a generator like this excuses us from knowing the code we write. We should all learn how CSS Grid and Flexbox work. Even if your stronghold is JavaScript, having a solid foundation in CSS knowledge is a powerful ally when communicating your ideas. When sharing a prototype for a component, a UX interaction, or even an algorithm in an online sandbox, the way in which your work is presented can make a big difference. The ability to develop proper layouts — and define the styles that create them — is fundamental.

Crafting layouts in CSS should not be a daunting task. CSS Grid is actually quite fun to use! For example, using named grid areas feels like an ASCII art version of drawing a design on a piece of paper. Lets create the layout of a photos app, a feed of pics and the people in them side by side for its main content and the typical header, footer and a config sidebar.

.photos-app {   /* For our app layout, lets place things in a grid */   display: grid;   /* We want 3 columns and 3 rows, and these are the responsive      track sizes using `fr` (fraction of the remaining space) */   grid-template-columns: 20% 1fr 1fr;   grid-template-rows: 0.5fr 1.7fr 0.3fr;   /* Let's separate our tracks a bit */   gap: 1em;   /* We now have 3x3 cells, here is where each section is placed */   grid-template-areas:     "header header header"  /* a header stretching in the top row */     "config photos people"  /* a left sidebar, and our app content */     "footer footer footer"; /* and a footer along the bottom row  */ } .the-header {   /* In each section, let's define the name we use to refence the area */   grid-area: "header"; }

This is just a small subset of what you can build with CSS Grid. The spec is quite flexible. Areas can also be placed directly using line numbers or names, or they can be placed implicitly by the browser, with the content distributed inside the grid automatically. And the spec continues to grow with additions, like subgrid.

At the same time, working with grids can be difficult, just like anything that requires a new way of thinking. It takes a lot of time to wrap our heads around this sort of thing. And one way to help do that is to…

Learn while playing

When you are learning CSS Grid, it is easy to feel intimidated by its notation and semantics. Until you develop some muscle memory for it, kickstarting the learning process with visual and interactive tools can be an excellent way to overcome that early trepidation. A lot of us have used generators while learning how to create shadows, gradients, Markdown tables, and so on. Generators, if built with care, are great learning aids.

Let’s use Layoutit Grid to recreate the same design in our example.

Open Layoutit Grid

Generators like this aren’t meant to be leaned on forever; they’re a stepping stone. This particular one helps you experience the power of CSS Grid by materializing your designs in a few clicks along with the code to make it happen. This gives you the early wins that you need to push forward with the learning process. For some of us, generators permanently remain in our toolboxes. Not because we do not know how to craft the layouts by hand, but because having the visual feedback loop help us to quickly convert our ideas into code. So we keep playing with them.

Sarah Drasner has also created a CSS Grid generator that’s worth checking out as well.

Learn by building

Leniolabs recently open-sourced Layoutit Grid and added new features, like interactive code views, area edition, history and offline support. And there are several more in the making.

View on GitHub

If you have ideas to improve the tool, get in touch! Open an issue and let’s discuss it on GitHub. Going into meta territory, you can also learn about the CSS Grid spec by helping us build the tool. 

We use the app to keep track of best practices in creating performant interactive web experiences. It is now powered by the newly released Vue 3 using <script setup> components and built with Vite, a new dev tool that doesn’t bundle the app while developing, which gives us instant feedback during development. If you are curious and want to build with us, fork the repo and let’s learn together!

The post Layoutit Grid: Learning CSS Grid Visually With a Generator appeared first on CSS-Tricks.

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

How to Create a Realistic Motion Blur with CSS Transitions

Css Tricks - Wed, 10/14/2020 - 4:47am

Before we delve into making a realistic motion blur in CSS, it’s worth doing a quick dive into what motion blur is, so we can have a better idea of what we’re trying to reproduce.

Have you ever taken a photo of something moving quickly, especially under low light, and it turned into a blurry streak? Or maybe the whole camera shook and the whole shot became a series of streaks? This is motion blur, and it’s a byproduct of how a camera works.

Motion Blur 101

Imagine a camera. It’s got a shutter, a door that opens to let light in, and then closes to stop the light from coming in. From the time it opens, to when it closes, is a single photograph, or a single frame of a moving image.

Real motion blur in action (Photo: Kevin Erdvig, Unsplash)

If the subject of the frame is moving during the time the shutter is open, we end up taking a photo of an object moving through the frame. On film, this shows up as being a steady smear, with the subject being in an infinite number of places between its starting point to its end. The moving object also ends up being semi-transparent, with parts of the background visible behind it.

What computers do to fake this is model several subframes, and then composite them together at a fraction of the opacity. Putting lots of copies of the same object in slightly different places along the path of motion creates a pretty convincing facsimile of a motion blur.

Video compositing apps tend to have settings for how many subdivisions their motion blur should have. If you set this value really low, you can see exactly how the technique works, like this, a frame of an animation of a simple white dot at four samples per frame:

Four samples per frame. Here is 12 samples per frame. And by the time we’re at 32 samples per frame, it’s pretty close to fully real, especially when seen at multiple frames per second.

The number of samples it takes to make a convincing motion blur is entirely relative to the content. Something small with sharp edges that’s moving super fast will need a lot of subframes; but something blurry moving slowly might need only a few. In general, using more will create a more convincing effect.

Doing this in CSS

In order to approximate this effect in CSS, we need to create a ton of identical elements, make them semi-transparent, and offset their animations by a tiny fraction of a second.

First, we’ll set up the base with the animation we want using a CSS transition. We’ll go with a simple black dot, and assign it a transform on hover (or tap, if you’re on mobile). We’ll also animate the border radius and color to show the flexibility of this approach.

Here is the base animation without motion blur:

CodePen Embed Fallback

Now, let’s make 20 identical copies of the black dot, all placed in the exact same place with absolute positioning. Each copy has an opacity of 10%, which is a little more than might be mathematically correct, but I find we need to make them more opaque to look solid enough.

The next step is where the magic happens. We add a slightly-increasing transition-delay value for each clone of our dot object. They’ll all run the exact same animation, but they’ll each be offset by three milliseconds. 

CodePen Embed Fallback

The beauty of this approach is that it creates a pseudo-motion blur effect that works for a ton of different animations. We can throw color changes on there, scaling transitions, odd timings, and the motion blur effect still works.

Using 20 object clones will work for plenty of fast and slow animations, but fewer can still produce a reasonable sense of motion blur. You may need to tweak the number of cloned objects, their opacity, and the amount of transition delay to work with your particular animation. The demo we just looked at has the blur effect slightly overclocked to make it more prominent.

Eventually, with the progress of computer power, I expect that some of the major browsers might start offering this effect natively. Then we can do away with the ridiculousness of having 20 identical objects. In the meantime, this is a reasonable way to approximate a realistic motion blur.

The post How to Create a Realistic Motion Blur with CSS Transitions appeared first on CSS-Tricks.

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

Netlify Edge Handlers

Css Tricks - Tue, 10/13/2020 - 4:39am

Some very cool news from Netlify: Edge Handlers are in Early Access (request it here). I think these couple of lines of code do a great job in explaining what an Edge Handler is:

export function onRequest(event) { console.log(`Incoming request for ${event.request.url}`); event.replaceResponse(() => fetch("")); }

So that’s a little bitty bit of JavaScript that runs at “the edge” (at the CDN level) for every request through your site. In the case above, I’m totally replacing the response with an Ajax request for another URL. Weird! But cool. This has incredible power. I can replace the response with a manipulated response (it could be just a small change). Say, change the headers. Or check who the logged-in user is, make a request for data on their behalf, and inject that data into the response. &#x1f92f;.

So you might think of Jamstack as either pre-render or get data client-side. This is opening up a new door: build your response dynamically at the edge.

What’s nice about the Netlify approach is that the code that runs these sits right alongside the rest of your code in the repo itself, just like functions.

The post Netlify Edge Handlers appeared first on CSS-Tricks.

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

Run Gulp as You Open a VS Code Project

Css Tricks - Mon, 10/12/2020 - 1:04pm

When I open my local project for this very site, there is a 100% chance that I need to run this command before anything else: gulp. I set that up fresh less than a year ago so I’m on the latest-and-greatest stuff and have my workflow just how I like it. I did a few more tweaks a few months later to make things a smidge nicer (even adding a fancy fun little dock icon!).

That’s when I learned about VS Code Tasks. Generically, the can just run command line tasks that you configure whenever you choose to run them by name. But I’m particularly compelled by the idea that they can run when you open a project.

It’s this easy to run Gulp:

{ "version": "2.0.0", "tasks": [ { "label": "Run Gulp", "command": "gulp", "type": "shell", "runOptions": { "runOn": "folderOpen" } } ] }

Except… that started to fail on my machine. I use nvm to manage Node versions, and despite my best effort to nvm alias default to the the correct version of Node that works nicely with Gulp, the Node version was always wrong, and thus running gulp would fail. The trick is to run nvm use first (which sets the correct version from my .nvmrc file), then gulp runs fine.

That works fine in a fresh terminal window, but for some reason, even making the command run two tasks like this (chaining them with a semicolon):

"command": "nvm use; gulp",

…it would still fail. It didn’t know what nvm meant. I don’t know what the heart of the problem is exactly (why one terminal doesn’t know the same things that another terminal does), but I did manage to sort out that the global nvm has a shell script with one job: defining the nvm command. So you “source” that, as they say, and then the nvm command works.

So my final setup is:

{ "version": "2.0.0", "tasks": [ { "label": "Run Gulp", "command": ". ~/.nvm/; nvm use; gulp", "type": "shell", "runOptions": { "runOn": "folderOpen" } } ] }

And that, dear readers, runs Gulp perfectly when I open my CSS-Tricks project, which is exactly what I wanted.

High five to Jen Luker who went on this journey with me and helped me get it to the finish line. &#x1f91a;

The post Run Gulp as You Open a VS Code Project appeared first on CSS-Tricks.

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

How to Recreate the Ripple Effect of Material Design Buttons

Css Tricks - Mon, 10/12/2020 - 4:52am

When I first discovered Material Design, I was particularly inspired by its button component. It uses a ripple effect to give users feedback in a simple, elegant way.

How does this effect work? Material Design’s buttons don’t just sport a neat ripple animation, but the animation also changes position depending on where each button is clicked.

We can achieve the same result. We’ll start with a concise solution using ES6+ JavaScript, before looking at a few alternative approaches.


Our goal is to avoid any extraneous HTML markup. So we’ll go with the bare minimum:

<button>Find out more</button> Styling the button

We’ll need to style a few elements of our ripple dynamically, using JavaScript. But everything else can be done in CSS. For our buttons, it’s only necessary to include two properties.

button {   position: relative;   overflow: hidden; }

Using position: relative allows us to use position: absolute on our ripple element, which we need to control its position. Meanwhile, overflow: hidden prevents the ripple from exceeding the button’s edges. Everything else is optional. But right now, our button is looking a bit old school. Here’s a more modern starting point:

/* Roboto is Material's default font */ @import url(''); button {   position: relative;   overflow: hidden;   transition: background 400ms;   color: #fff;   background-color: #6200ee;   padding: 1rem 2rem;   font-family: 'Roboto', sans-serif;   font-size: 1.5rem;   outline: 0;   border: 0;   border-radius: 0.25rem;   box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.3);   cursor: pointer; } Styling the ripples

Later on, we’ll be using JavaScript to inject ripples into our HTML as spans with a .ripple class. But before turning to JavaScript, let’s define a style for those ripples in CSS so we have them at the ready:

span.ripple {   position: absolute; /* The absolute position we mentioned earlier */   border-radius: 50%;   transform: scale(0);   animation: ripple 600ms linear;   background-color: rgba(255, 255, 255, 0.7); }

To make our ripples circular, we’ve set the border-radius to 50%. And to ensure each ripple emerges from nothing, we’ve set the default scale to 0. Right now, we won’t be able to see anything because we don’t yet have a value for the top, left, width, or height properties; we’ll soon be injecting these properties with JavaScript.

As for our CSS, the last thing we need to add is an end state for the animation:

@keyframes ripple {   to {     transform: scale(4);     opacity: 0;   } }

Notice that we’re not defining a starting state with the from keyword in the keyframes? We can omit from and CSS will construct the missing values based on those that apply to the animated element. This occurs if the relevant values are stated explicitly — as in transform: scale(0) — or if they’re the default, like opacity: 1.

Now for the JavaScript

Finally, we need JavaScript to dynamically set the position and size of our ripples. The size should be based on the size of the button, while the position should be based on both the position of the button and of the cursor.

We’ll start with an empty function that takes a click event as its argument:

function createRipple(event) {   // }

We’ll access our button by finding the currentTarget of the event.

const button = event.currentTarget;

Next, we’ll instantiate our span element, and calculate its diameter and radius based on the width and height of the button.

const circle = document.createElement("span"); const diameter = Math.max(button.clientWidth, button.clientHeight); const radius = diameter / 2;

We can now define the remaining properties we need for our ripples: the left, top, width and height. = = `${diameter}px`; = `${event.clientX - (button.offsetLeft + radius)}px`; = `${event.clientY - (button.offsetTop + radius)}px`; circle.classList.add("ripple"); 

Before adding our span element to the DOM, it’s good practice to check for any existing ripples that might be leftover from previous clicks, and remove them before executing the next one.

const ripple = button.getElementsByClassName("ripple")[0]; if (ripple) {   ripple.remove(); }

As a final step, we append the span as a child to the button element so it is injected inside the button.


With our function complete, all that’s left is to call it. This could be done in a number of ways. If we want to add the ripple to every button on our page, we can use something like this:

const buttons = document.getElementsByTagName("button"); for (const button of buttons) {   button.addEventListener("click", createRipple); }

We now have a working ripple effect!

CodePen Embed Fallback Taking it further

What if we want to go further and combine this effect with other changes to our button’s position or size? The ability to customize is, after all, one of the main advantages we have by choosing to recreate the effect ourselves. To test how easy it is to extend our function, I decided to add a “magnet” effect, which causes our button to move towards our cursor when the cursor’s within a certain area.

We need to rely on some of the same variables defined in the ripple function. Rather than repeating code unnecessarily, we should store them somewhere they’re accessible to both methods. But we should also keep the shared variables scoped to each individual button. One way to achieve this is by using classes, as in the example below:

CodePen Embed Fallback

Since the magnet effect needs to keep track of the cursor every time it moves, we no longer need to calculate the cursor position to create a ripple. Instead, we can rely on cursorX and cursorY.

Two important new variables are magneticPullX and magneticPullY. They control how strongly our magnet method pulls the button after the cursor. So, when we define the center of our ripple, we need to adjust for both the position of the new button (x and y) and the magnetic pull.

const offsetLeft = this.left + this.x * this.magneticPullX; const offsetTop = + this.y * this.magneticPullY;

To apply these combined effects to all our buttons, we need to instantiate a new instance of the class for each one:

const buttons = document.getElementsByTagName("button"); for (const button of buttons) {   new Button(button); } Other techniques

Of course, this is only one way to achieve a ripple effect. On CodePen, there are lots of examples that show different implementations. Below are some of my favourites.


If a user has disabled JavaScript, our ripple effect doesn’t have any fallbacks. But it’s possible to get close to the original effect with just CSS, using the :active pseudo-class to respond to clicks. The main limitation is that the ripple can only emerge from one spot — usually the center of the button — rather than responding to the position of our clicks. This example by Ben Szabo is particularly concise:

CodePen Embed Fallback Pre-ES6 JavaScript

Leandro Parice’s demo is similar to our implementation but it’s compatible with earlier versions of JavaScript: 

CodePen Embed Fallback jQuery 

This example use jQuery to achieve the ripple effect. If you already have jQuery as a dependency, it could help save you a few lines of code. 

CodePen Embed Fallback React

Finally, one last example from me. Although it’s possible to use React features like state and refs to help create the ripple effect, these aren’t strictly necessary. The position and size of the ripple both need to be calculated for every click, so there’s no advantage to holding that information in state. Plus, we can access our button element from the click event, so we don’t need refs either.

This React example uses a createRipple function identical to that of this article’s first implementation. The main difference is that — as a method of the Button component — our function is scoped to that component. Also, the onClick event listener is now part of our JSX:

CodePen Embed Fallback

The post How to Recreate the Ripple Effect of Material Design Buttons appeared first on CSS-Tricks.

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

Animating Number Counters

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

Number animation, as in, imagine a number changing from 1 to 2, then 2 to 3, then 3 to 4, etc. over a specified time. Like a counter, except controlled by the same kind of animation that we use for other design animation on the web. This could be useful when designing something like a dashboard, to bring a little pizazz to the numbers. Amazingly, this can now be done in CSS without much trickery. You can jump right to the new solution if you like, but first let’s look at how we used to do it.

One fairly logical way to do number animation is by changing the number in JavaScript. We could do a rather simple setInterval, but here’s a fancier answer with a function that accepts a start, end, and duration, so you can treat it more like an animation:

CodePen Embed Fallback

Keeping it to CSS, we could use CSS counters to animate a number by adjusting the count at different keyframes:

CodePen Embed Fallback

Another way would be to line up all the numbers in a row and animate the position of them only showing one at a time:

CodePen Embed Fallback

Some of the repetitive code in these examples could use a preprocessor like Pug for HTML or SCSS for CSS that offer loops to make them perhaps easier to manage, but use vanilla on purpose so you can see the fundamental ideas.

The New School CSS Solution

With recent support for CSS.registerProperty and @property, we can animate CSS variables. The trick is to declare the CSS custom property as an integer; that way it can be interpolated (like within a transition) just like any other integer.

@property --num {   syntax: '<integer>';   initial-value: 0;   inherits: false; } div {   transition: --num 1s;   counter-reset: num var(--num); } div:hover {   --num: 10000; } div::after {   content: counter(num); }

Important Note: At the time of this writing, this @property syntax is only supported in Chrome ( and other Chromium core browsers like Edge and Opera), so this isn’t cross-browser friendly. If you’re building something Chrome-only (e.g. an Electron app) it’s useful right away, if not, wait. The demos from above are more widely supported.

The CSS content property can be used to display the number, but we still need to use counter to convert the number to a string because content can only output <string> values.

CodePen Embed Fallback

See how we can ease the animations just like any other animation? Super cool! 

Typed CSS variables can also be used in @keyframes: 

CodePen Embed Fallback

One downside? Counters only support integers. That means decimals and fractions are out of the question. We’d have to display the integer part and fractional part separately somehow.

Can we animate decimals?

It’s possible to convert a decimal (e.g. --number) to an integer. Here’s how it works:

  1. Register an <integer> CSS variable ( e.g. --integer ), with the initial-value specified
  2. Then use calc() to round the value: --integer: calc(var(--number))

In this case, --number will be rounded to the nearest integer and store the result into --integer.

@property --integer {   syntax: "<integer>";   initial-value: 0;   inherits: false; } --number: 1234.5678; --integer: calc(var(--number)); /* 1235 */

Sometimes we just need the integer part. There is a tricky way to do it: --integer: max(var(--number) - 0.5, 0). This works for positive numbers. calc() isn’t even required this way.

/* @property --integer */ --number: 1234.5678; --integer: max(var(--number) - 0.5, 0); /* 1234 */

We can extract the fractional part in a similar way, then convert it into string with counter (but remember that content values must be strings). To display concatenated strings, use following syntax:

content: "string1" var(--string2) counter(--integer) ...

Here’s a full example that animates percentages with decimals:

CodePen Embed Fallback Other tips

Because we’re using CSS counters, the format of those counters can be in other formats besides numbers. Here’s an example of animating the letters “CSS” to “YES”!

CodePen Embed Fallback

Oh and here’s another tip: we can debug the values grabbing the computed value of the custom property with JavaScript:


That’s it! It’s amazing what CSS can do these days.

The post Animating Number Counters appeared first on CSS-Tricks.

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

Balancing on a Pivot with Flexbox

Css Tricks - Thu, 10/08/2020 - 4:44am

Let me show you a way I recently discovered to center a bunch of elements around what I call the pivot. I promise you that funky HTML is out of the question and you won’t need to know any bleeding-edge CSS to get the job done.

I’m big on word games, so I recently re-imagined the main menu of my website as a nod to crossword puzzles, with my name as the vertical word, and the main sections of my website across the horizontals.

Here’s how the design looks with the names of some colors instead:

And here’s a sample of the HTML that drives this puzzle:

<div class="puzzle"> <div class="word"> <span class="letter">i</span> <span class="letter">n</span> <span class="letter">d</span> <span class="letter">i</span> <span class="letter pivot">g</span> <span class="letter">o</span> </div> <!-- MORE WORDS --> </div>

In this example, the letter g is the pivot. See how it’s not at the halfway mark? That’s the beauty of this challenge.

We could apply an offset to each word using hard-coded CSS or inline custom properties and walk away. It certainly gets an award for being the most obvious way to solve the problem, but there’s a downside — in addition to the .pivot class, we’d have to specify an offset for every word. The voice in my head tells me that’s adding unnecessary redundancy, is less flexible, and requires extra baggage we don’t need every time we add or change a word.

Let’s take a step back instead and see how the puzzle looks without any balancing:

Imagine for a moment that we use display: none to hide all of the letters before the pivot; now all we can see are the pivots and everything after them:

With no further changes, our pivots would already be aligned. But we’ve lost the start of our words, and when we reintroduce the hidden parts, each word gets pushed out to the right and everything is out of whack again.

If we were to hide the trailing letters instead, we’d still be left with misaligned pivots:

All of this back-and-forth seems a bit pointless, but it reveals a symmetry to my problem. If we were to use a right-to-left (RTL) reading scheme, we’d have the opposite problem — we’d be able to solve the right side but the left would be all wrong.

Wouldn’t it be great if there was a way to have both sides line up at the same time?

As a matter of fact, there is.

Given we already have half a solution, let’s borrow a concept from algorithmics called divide and conquer. The general idea is that we can break a problem down into parts, and that by finding a solution for the parts, we’ll find a solution for the whole.

In that case, let’s break our problem down into the positioning of two parts. First is the “head” or everything before the pivot.

Next is the “tail” which is the pivot plus everything after it.

The flex display type will help us here; if you’re not familiar with it, flex is a framework for positioning elements in one-dimension. The trick here is to take advantage of the left and right ends of our container to enforce alignment. To make it work, we’ll swap the head and tail parts by using a smaller order  property value on the tail than the head. The order property is used by flex to determine the sequence of elements in a flexible layout. Smaller numbers are placed earlier in the flow.

To distinguish the head and tail elements without any extra HTML, we can apply styles to the head part to all of the letters, after which we’ll make use of the cascading nature of CSS to override the pivot and everything after it using the subsequent-sibling selector .pivot ~ .letter.

Here’s how things look now:

Okay, so now the head is sitting flush up against the end of the tail. Hang on, don’t go kicking up a stink about it! We can fix this by applying margin: auto to the right of the last element in the tail. That just so happens to also be the last letter in the word which is now sitting somewhere in the middle. The addition of an auto margin serves to push the head away from the tail and all the way over to the right-hand side of our container.

Now we have something that looks like this:

The only thing left is stitch our pieces back together in the right order. This is easy enough to do if we apply position: relative to all of our letters and then chuck a left: 50% on the tail and a right: 50% on our head items.

Here’s a generalized version of the code we just used. As you can see, it’s just 15 lines of simple CSS:

.container {   display: flex; } .item:last-child {   margin-right: auto; } .item {   order: 2;   position: relative;   right: 50%; } .pivot, .pivot ~ .item {   order: 1;   left: 50%; }

It’s also feasible to use this approach for vertical layouts by setting the flex-direction to a column value. It should also be said that the same can be achieved by sticking the head and tail elements in their own wrappers — but that would require more markup and verbose CSS while being a lot less flexible. What if, for example, our back-end is already generating an unwrapped list of elements with dynamically generated classes?

Quite serendipitously, this solution also plays well with screen readers. Although we’re ordering the two sections backwards, we’re then shifting them back into place via relative positioning, so the final ordering of elements matches our markup, albeit nicely centered.

Screen readers preserve the element ordering as per the original markup.

Here’s the final example on CodePen:

CodePen Embed Fallback Conclusion

Developers are better at balancing than acrobats. Don’t believe me? Think about it: many of the common challenges we face require finding a sweet spot between competing requirements ranging from performance and readability, to style and function, and even scalability and simplicity. A balancing act, no doubt.

But the point at which we find balance isn’t always midway between one thing and another. Balance is often found at some inexplicable point in between; or, as we’ve just seen, around an arbitrary HTML element.

So there you have it! Go and tell your friends that you’re the greatest acrobat around.

The post Balancing on a Pivot with Flexbox appeared first on CSS-Tricks.

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

The Widening Responsibility for Front-End Developers

Css Tricks - Wed, 10/07/2020 - 4:48am

This is an extended version of my essay “When front-end means full-stack” which was published in the wonderful Increment magazine put out by Stripe. It’s also something of an evolution of a couple other of my essays, “The Great Divide” and “Ooops, I guess we’re full-stack developers now.”

The moment I fell in love with front-end development was when I discovered the style.css file in WordPress themes. That’s where all the magic was (is!) to me. I could (can!) change a handful of lines in there and totally change the look and feel of a website. It’s an incredible game to play.

Back when I was cowboy-coding over FTP. Although I definitely wasn’t using CSS grid!

By fiddling with HTML and CSS, I can change the way you feel about a bit of writing. I can make you feel more comfortable about buying tickets to an event. I can increase the chances you share something with your friends.

That was well before anybody paid me money to be a front-end developer, but even then I felt the intoxicating mix of stimuli that the job offers. Front-end development is this expressive art form, but often constrained by things like the need to directly communicate messaging and accomplish business goals.

Front-end development is at the intersection of art and logic. A cross of business and expression. Both left and right brain. A cocktail of design and nerdery.

I love it.

Looking back at the courses I chose from middle school through college, I bounced back and forth between computer-focused classes and art-focused classes, so I suppose it’s no surprise I found a way to do both as a career.

The term “Front-End Developer” is fairly well-defined and understood. For one, it’s a job title. I’ll bet some of you literally have business cards that say it on there, or some variation like: “Front-End Designer,” “UX Developer,” or “UI Engineer.” The debate around what those mean isn’t particularly interesting to me. I find that the roles are so varied from job-to-job and company-to-company that job titles will never be enough to describe things. Getting this job is more about demonstrating you know what you’re doing more than anything else¹.

Chris Coyier
Front-End Developer

The title variations are just nuance. The bigger picture is that as long as the job is building websites, front-enders are focused on the browser. Quite literally:

  • front-end = browsers
  • back-end = servers

Even as the job has changed over the decades, that distinction still largely holds.

As “browser people,” there are certain truths that come along for the ride. One is that there is a whole landscape of different browsers and, despite the best efforts of standards bodies, they still behave somewhat differently. Just today, as I write, I dealt with a bug where a date string I had from an API was in a format such that Firefox threw an error when I tried to use the .toISOString() JavaScript API on it, but was fine in Chrome. That’s just life as a front-end developer. That’s the job.

Even across that landscape of browsers, just on desktop computers, there is variance in how users use that browser. How big do they have the window open? Do they have dark mode activated on their operating system? How’s the color gamut on that monitor? What is the pixel density? How’s the bandwidth situation? Do they use a keyboard and mouse? One or the other? Neither? All those same questions apply to mobile devices too, where there is an equally if not more complicated browser landscape. And just wait until you take a hard look at HTML emails.

That’s a lot of unknowns, and the answers to developing for that unknown landscape is firmly in the hands of front-end developers.

Into the unknoooooowwwn. – Elsa

The most important aspect of the job? The people that use these browsers. That’s why we’re building things at all. These are the people I’m trying to impress with my mad CSS skills. These are the people I’m trying to get to buy my widget. Who all my business charts hinge upon. Who’s reaction can sway my emotions like yarn in the breeze. These users, who we put on a pedestal for good reason, have a much wider landscape than the browsers do. They speak different languages. They want different things. They are trying to solve different problems. They have different physical abilities. They have different levels of urgency. Again, helping them is firmly in the hands of front-end developers. There is very little in between the characters we type into our text editors and the users for whom we wish to serve.

Being a front-end developer puts us on the front lines between the thing we’re building and the people we’re building it for, and that’s a place some of us really enjoy being.

That’s some weighty stuff, isn’t it? I haven’t even mentioned React yet.

The “we care about the users” thing might feel a little precious. I’d think in a high functioning company, everyone would care about the users, from the CEO on down. It’s different, though. When we code a <button>, we’re quite literally putting a button into a browser window that users directly interact with. When we adjust a color, we’re adjusting exactly what our sighted users see when they see our work.

That’s not far off from a ceramic artist pulling a handle out of clay for a coffee cup. It’s applying craftsmanship to a digital experience. While a back-end developer might care deeply about the users of a site, they are, as Monica Dinculescu once told me in a conversation about this, “outsourcing that responsibility.”

We established that front-end developers are browser people. The job is making things work well in browsers. So we need to understand the languages browsers speak, namely: HTML, CSS, and JavaScript². And that’s not just me being some old school fundamentalist; it’s through a few decades of everyday front-end development work that knowing those base languages is vital to us doing a good job. Even when we don’t work directly with them (HTML might come from a template in another language, CSS might be produced from a preprocessor, JavaScript might be mostly written in the parlance of a framework), what goes the browser is ultimately HTML, CSS, and JavaScript, so that’s where debugging largely takes place and the ability of the browser is put to work.

CSS will always be my favorite and HTML feels like it needs the most love — but JavaScript is the one we really need to examine The last decade has seen JavaScript blossom from a language used for a handful of interactive effects to the predominant language used across the entire stack of web design and development. It’s possible to work on websites and writing nothing but JavaScript. A real sea change.

JavaScript is all-powerful in the browser. In a sense, it supersedes HTML and CSS, as there is nothing either of those languages can do that JavaScript cannot. HTML is parsed by the browser and turned into the DOM, which JavaScript can also entirely create and manipulate. CSS has its own model, the CSSOM, that applies styles to elements in the DOM, which JavaScript can also create and manipulate.

This isn’t quite fair though. HTML is the very first file that browsers parse before they do the rest of the work needed to build the site. That firstness is unique to HTML and a vital part of making websites fast.

In fact, if the HTML was the only file to come across the network, that should be enough to deliver the basic information and functionality of a site.

That philosophy is called Progressive Enhancement. I’m a fan, myself, but I don’t always adhere to it perfectly. For example, a <form> can be entirely functional in HTML, when it’s action attribute points to a URL where the form can be processed. Progressive Enhancement would have us build it that way. Then, when JavaScript executes, it takes over the submission and has the form submit via Ajax instead, which might be a nicer experience as the page won’t have to refresh. I like that. Taken further, any <button> outside a form is entirely useless without JavaScript, so in the spirit of Progressive Enhancement, I should wait until JavaScript executes to even put that button on the page at all (or at least reveal it). That’s the kind of thing where even those of us with the best intentions might not always toe the line perfectly. Just put the button in, Sam. Nobody is gonna die.

JavaScript’s all-powerfulness makes it an appealing target for those of us doing work on the web — particularly as JavaScript as a language has evolved to become even more powerful and ergonomic, and the frameworks that are built in JavaScript become even more-so. Back in 2015, it was already so clear that JavaScript was experiencing incredible growth in usage, Matt Mullenweg, co-founder of WordPress, gave the developer world homework: “Learn JavaScript Deeply”³. He couldn’t have been more right. Half a decade later, JavaScript has done a good job of taking over front-end development. Particularly if you look at front-end development jobs.

While the web almanac might show us that only 5% of the top-zillion sites use React compared to 85% including jQuery, those numbers are nearly flipped when looking around at front-end development job requirements.

I’m sure there are fancy economic reasons for all that, but jobs are as important and personal as it gets for people, so it very much matters.

So we’re browser people in a sea of JavaScript building things for people. If we take a look at the job at a practical day-to-day tasks level, it’s a bit like this:

  • Translate designs into code
  • Think in terms of responsive design, allowing us to design and build across the landscape of devices
  • Build systemically. Construct components and patterns, not one-offs.
  • Apply semantics to content
  • Consider accessibility
  • Worry about the performance of the site. Optimize everything. Reduce, reuse, recycle.

Just that first bullet point feels like a college degree to me. Taken together, all of those points certainly do.

This whole list is a bit abstract though, so let’s apply it to something we can look at. What if this website was our current project?

Our brains and fingers go wild!

  • Let’s build the layout with CSS grid. 
  • What fonts are those? Do we need to load them in their entirety or can we subset them? What happens as they load in? This layout feels like it will really suffer from font-shifting jank. 
  • There are some repeated patterns here. We should probably make a card design pattern. Every website needs a good card pattern. 
  • That’s a gorgeous color scheme. Are the colors mathematically related? Should we make variables to represent them individually or can we just alter a single hue as needed? Are we going to use custom properties in our CSS? Colors are just colors though, we might not need the cascading power of them just for this. Should we just use Sass variables? Are we going to use a CSS preprocessor at all?
  • The source order is tricky here. We need to order things so that they make sense for a screen reader user. We should have a meeting about what the expected order of content should be, even if we’re visually moving things around a bit with CSS grid.
  • The photographs here are beautifully shot. But some of them match the background color of the site… can we get away with alpha-transparent PNGs here? Those are always so big. Can any next-gen formats help us? Or should we try to match the background of a JPG with the background of the site seamlessly. Who’s writing the alt text for these?
  • There are some icons in use here. Inline SVG, right? Certainly SVG of some kind, not icon fonts, right? Should we build a whole icon system? I guess it depends on how we’re gonna be building this thing more broadly. Do we have a build system at all?
  • What’s the whole front-end plan here? Can I code this thing in vanilla HTML, CSS, and JavaScript? Well, I know I can, but what are the team expectations? Client expectations? Does it need to be a React thing because it’s part of some ecosystem of stuff that is already React? Or Vue or Svelte or whatever? Is there a CMS involved?
  • I’m glad the designer thought of not just the “desktop” and “mobile” sizes but also tackled an in-between size. Those are always awkward. There is no interactivity information here though. What should we do when that search field is focused? What gets revealed when that hamburger is tapped? Are we doing page-level transitions here?

I could go on and on. That’s how front-end developers think, at least in my experience and in talking with my peers.

A lot of those things have been our jobs forever though. We’ve been asking and answering these questions on every website we’ve built for as long as we’ve been doing it. There are different challenges on each site, which is great and keeps this job fun, but there is a lot of repetition too.

Allow me to get around to the title of this article. 

While we’ve been doing a lot of this stuff for ages, there is a whole pile of new stuff we’re starting to be expected to do, particularly if we’re talking about building the site with a modern JavaScript framework. All the modern frameworks, as much as they like to disagree about things, agree about one big thing: everything is a component. You nest and piece together components as needed. Even native JavaScript moves toward its own model of Web Components.

I like it, this idea of components. It allows you and your team to build the abstractions that make the most sense to you and what you are building.

Your Card component does all the stuff your card needs to do. Your Form component does forms how your website needs to do forms. But it’s a new concept to old developers like me. Components in JavaScript have taken hold in a way that components on the server-side never did. I’ve worked on many a WordPress website where the best I did was break templates into somewhat arbitrary include() statements. I’ve worked on Ruby on Rails sites with partials that take a handful of local variables. Those are useful for building re-usable parts, but they are a far cry from the robust component models that JavaScript frameworks offer us today.

All this custom component creation makes me a site-level architect in a way that I didn’t use to be. Here’s an example. Of course I have a Button component. Of course I have an Icon component. I’ll use them in my Card component. My Card component lives in a Grid component that lays them out and paginates them. The whole page is actually built from components. The Header component has a SearchBar component and a UserMenu component. The Sidebar component has a Navigation component and an Ad component. The whole page is just a special combination of components, which is probably based on the URL, assuming I’m all-in on building our front-end with JavaScript. So now I’m dealing with URLs myself, and I’m essentially the architect of the entire site. [Sweats profusely]

Like I told ya, a whole pile of new responsibility.

Components that are in charge of displaying content are almost certainly not hard-coded with data in them. They are built to be templates. They are built to accept data and construct themselves based on that data. In the olden days, when we were doing this kind of templating, the data has probably already arrived on the page we’re working on. In a JavaScript-powered app, it’s more likely that that data is fetched by JavaScript. Perhaps I’ll fetch it when the component renders. In a stack I’m working with right now, the front end is in React, the API is in GraphQL and we use Apollo Client to work with data. We use a special “hook” in the React components to run the queries to fetch the data we need, and another special hook when we need to change that data. Guess who does that work? Is it some other kind of developer that specializes in this data layer work? No, it’s become the domain of the front-end developer.

Speaking of data, there is all this other data that a website often has to deal with that doesn’t come from a database or API. It’s data that is really only relevant to the website at this moment in time.

  • Which tab is active right now?
  • Is this modal dialog open or closed?
  • Which bar of this accordion is expanded?
  • Is this message bar in an error state or warning state?
  • How many pages are you paginated in?
  • How far is the user scrolled down the page?

Front-end developers have been dealing with that kind of state for a long time, but it’s exactly this kind of state that has gotten us into trouble before. A modal dialog can be open with a simple modifier class like <div class="modal is-open"> and toggling that class is easy enough with .classList.toggle(".is-open"); But that’s a purely visual treatment. How does anything else on the page know if that modal is open or not? Does it ask the DOM? In a lot of jQuery-style apps of yore, yes, it would. In a sense, the DOM became the “source of truth” for our websites. There were all sorts of problems that stemmed from this architecture, ranging from a simple naming change destroying functionality in weirdly insidious ways, to hard-to-reason-about application logic making bug fixing a difficult proposition.

Front-end developers collectively thought: what if we dealt with state in a more considered way? State management, as a concept, became a thing. JavaScript frameworks themselves built the concept right in, and third-party libraries have paved and continue to pave the way. This is another example of expanding responsibility. Who architects state management? Who enforces it and implements it? It’s not some other role, it’s front-end developers.

There is expanding responsibility in the checklist of things to do, but there is also work to be done in piecing it all together. How much of this state can be handled at the individual component level and how much needs to be higher level? How much of this data can be gotten at the individual component level and how much should be percolated from above? Design itself comes into play. How much of the styling of this component should be scoped to itself, and how much should come from more global styles?

It’s no wonder that design systems have taken off in recent years. We’re building components anyway, so thinking of them systemically is a natural fit.

Let’s look at our design again:

A bunch of new thoughts can begin!

  • Assuming we’re using a JavaScript framework, which one? Why? 
  • Can we statically render this site, even if we’re building with a JavaScript framework? Or server-side render it? 
  • Where are those recipes coming from? Can we get a GraphQL API going so we can ask for whatever we need, whenever we need it?
  • Maybe we should pick a CMS that has an API that will facilitate the kind of front-end building we want to do. Perhaps a headless CMS?
  • What are we doing for routing? Is the framework we chose opinionated or unopinionated about stuff like this?

  • What are the components we need? A Card, Icon, SearchForm, SiteMenu, Img… can we scaffold these out? Should we start with some kind of design framework on top of the base framework?
  • What’s the client state we might need? Current search term, current tab, hamburger open or not, at least.
  • Is there a login system for this site or not? Are logged in users shown anything different? 
  • Is there are third-party componentry we can leverage here?
  • Maybe we can find one of those fancy image components that does blur-up loading and lazy loading and all that.

Those are all things that are in the domain of front-end developers these days, on top of everything that we already need to do. Executing the design, semantics, accessibility, performance… that’s all still there. You still need to be proficient in HTML, CSS, JavaScript, and how the browser works. Being a front-end developer requires a haystack of skills that grows and grows. It’s the natural outcome of the web getting bigger. More people use the web and internet access grows. The economy around the web grows. The capability of browsers grows. The expectations of what is possible on the web grows. There isn’t a lot shrinking going on around here.

We’ve already reached the point where most front-end developers don’t know the whole haystack of responsibilities. There are lots of developers still doing well for themselves being rather design-focused and excelling at creative and well-implemented HTML and CSS, even as job posts looking for that dwindle.

There are systems-focused developers and even entire agencies that specialize in helping other companies build and implement design systems. There are data-focused developers that feel most at home making the data flow throughout a website and getting hot and heavy with business logic. While all of those people might have “front-end developer” on their business card, their responsibilities and even expectations of their work might be quite different. It’s all good, we’ll find ways to talk about all this in time.

In fact, how we talk about building websites has changed a lot in the last decade. Some of my early introduction to web development was through WordPress. WordPress needs a web server to run, is written in PHP, and stores it’s data in a MySQL database. As much as WordPress has evolved, all that is still exactly the same. We talk about that “stack” with an acronym: LAMP, or Linux, Apache, MySQL and PHP. Note that literally everything in the entire stack consists of back-end technologies. As a front-end developer, nothing about LAMP is relevant to me.

But other stacks have come along since then. A popular stack was MEAN (Mongo, Express, Angular and Node). Notice how we’re starting to inch our way toward more front-end technologies? Angular is a JavaScript framework, so as this stack gained popularity, so too did talking about the front-end as an important part of the stack. Node and Express are both JavaScript as well, albeit the server-side variant.

The existence of Node is a huge part of this story. Node isn’t JavaScript-like, it’s quite literally JavaScript. It makes a front-end developer already skilled in JavaScript able to do server-side work without too much of a stretch.

“Serverless” is a much more modern tech buzzword, and what it’s largely talking about is running small bits of code on cloud servers. Most often, those small bits of code are in Node, and written by JavaScript developers. These days, a JavaScript-focused front-end developer might be writing their own serverless functions and essentially being their own back-end developer. They’ll think of themselves as full-stack developers, and they’ll be right.

Shawn Wang coined a term for a new stack this year: STAR or Design System, TypeScript, Apollo, and React. This is incredible to me, not just because I kind of like that stack, but because it’s a way of talking about the stack powering a website that is entirely front-end technologies. Quite a shift.

I apologize if I’ve made you feel a little anxious reading this. If you feel like you’re behind in understanding all this stuff, you aren’t alone.

In fact, I don’t think I’ve talked to a single developer who told me they felt entirely comfortable with the entire world of building websites. Everybody has weak spots or entire areas where they just don’t know the first dang thing. You not only can specialize, but specializing is a pretty good idea, and I think you will end up specializing to some degree whether you plan to or not. If you have the good fortune to plan, pick things that you like. You’ll do just fine.

The only constant in life is change.

– Heraclitus     – Motivational Poster         – Chris Coyier

¹ I’m a white dude, so that helps a bunch, too. ↩️
² Browsers speak a bunch more languages. HTTP, SVG, PNG… The more you know the more you can put to work! ↩️
³ It’s an interesting bit of irony that WordPress websites generally aren’t built with client-side JavaScript components. ↩️

The post The Widening Responsibility for Front-End Developers appeared first on CSS-Tricks.

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

Looking at AWS Amplify

Css Tricks - Tue, 10/06/2020 - 1:11pm

AWS Amplify is a collection of tools from AWS to help you build applications.

Allow me to set the stage here to try to make that as clear as I know how. I have a friend (true story) who wants to build an app centered around physical training. His wife is a physical trainer, and they think perhaps there is some money to be made. It’s not entirely specced out, but perhaps the app sells access to personalized training programs, offers customized diets, exercise videos, and does the scheduling for one-on-one consultations. Sounds smart to me! Assuming they prove out the idea to some degree, it’s time to put their development skills to work and get to building.

A lot of the needs of an app like this map directly and easily to Amplify. A developer starting to plan might think like this:

  • We need to host this somewhere… Amplify has Static Web Hosting. And it’s fully featured with the fancy DX we’re starting to except these days: I connect a Git repo, and it will not only do deployment to CDN-backed global static hosting based on commits, but it will run my CI/CD (e.g. run tests) and give me URLs for previewing feature branches. You do all this with the AWS Amplify Console.
  • We need to do user authentication... The whole point here is that users can log in to get access to their stuff. Amplify helps with this (it’s Amazon Cognito built-in), which allows for typical sign-up/sign-in/forgot-password stuff, but also all the social login stuff you would expect. This is an example of what Amplify does: it helps abstract and build out underlying cloud services with minimal code.
  • We need data storage… Ideally, it’s managed with GraphQL because my modern front-end really benefits from that (perhaps it’s a React app). Amplify has that. It’s AWS AppSync built-in, which means you can use any type of data store, but get amazing features on top, like the GraphQL endpoints, realtime data syncing, and offline support.

That’s just the basics. All of that is extremely well-covered.

How do we set all this stuff up? This is one of the best parts: there is a CLI to help do everything. For example, about that data storage stuff, how do we get going with that? Once the CLI is installed and we’ve run amplify init in the project, we do amplify add api and we’ll be walked through it.

Now for this physical training app, we’ll need some static file storage as well. Maybe all the users have custom avatars, and the videos themselves need protected hosting. Well, we’re in AWS land here, so S3 buckets are a perfect fit. How? amplify add storage and we’ll be walked through it and of course, there are docs.

Impressive, really. We can build almost this entire thing with Amplify.

The one time we might have to reach out to another service is to handle payments. Stripe is usually the first choice of developers because of their great DX and robust APIs. They are built exactly for apps like this. We’d do our communicating with Stripe APIs over serverless functions. And guess what? We’re in AWS land here, so we have access to Lambdas, the best serverless function provider there is. The trick is that we can have our GraphQL setup, via AppSync, call a Lambda which can communicate with any outside API. Fortunately, there is a detailed walkthrough here from Ramon Postulart.

The guide to add Payments to your React Native App with Stripe, Expo and AWS Amplify by @ramonpostulart

— AWS Amplify (@AWSAmplify) May 22, 2020

And here’s another approach from Beez Fedia.

So here’s what I think is important to know:

  • Amplify is a helper. AWS offers tons of cloud services. Amplify helps you tie them together and get started using the important ones that you need.
  • The static hosting is the foundation for a web project. This is a Jamstack approach. But even that isn’t required, you can, for example, build an iOS app with the tools.
  • AWS is the biggest cloud provider in the world and powers many of the world’s biggest websites. You can build a personal project here and typically do it under the free tier, but you’ll never need to worry about scaling. You’re at the right place for scaling.
  • There is a lot to explore. If you wake up one day and want to add push notifications or explore something like machine learning, that stuff is there too.

If you’ve read this far, I think this quick high-level video will land better:

Other Resources

The post Looking at AWS Amplify appeared first on CSS-Tricks.

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

On the Web Share API

Css Tricks - Mon, 10/05/2020 - 12:03pm

I think the Web Share API is very cool (here’s our coverage). In a nutshell, it taps into the native sharing features on whatever platform you’re on, if that platform supports it.

I like this:

Web Share API activated on iOS

A heck of a lot more than these things:

This is just an image, don’t try to click them. You clicked them didn’t you?


  • The Web Share API is just a couple of lines of code. Easy! No images, no weighty JavaScript or iframes, no chance of going out of date (cough, Google+).
  • The UI that users see is customized to their platform and perhaps even customized by them to have the things they want in it.

Good job, web standards.

But it’s not supported everywhere. For example, I’m writing this blog post in Chrome, and it doesn’t work in desktop Chrome. But it does work in desktop Safari!

So if I’m going to use it, I’d rather test for support before plunking the button on a page. It’s very easy:

if (navigator.share) { }

Here’s an example where I plop a <button> onto an article, should that API be supported:

CodePen Embed Fallback

That JavaScript does a little fancy dancing to grab the title and first paragraph of the post to use in the API. I like how Jeremy Keith does it at the page level:

if (navigator.share) { navigator.share( { title: document.querySelector('title').textContent, text: document.querySelector('meta[name="description"]').getAttribute('content'), url: document.querySelector('link[rel="canonical"]').getAttribute('href') } ); }

You could just pass in strings to those values too. This is just showing off how you might do things dynamically that work on any page.

Jeremy has also been on a kick advocating for a JavaScript-optional version of the Web Share API, which he thinks could work like this:

<button type="share">

And then, for specifying title and text:

<button type="share" value="title,text">

That feels a little funky to me, with the comma. What if the title has a comma in it? And what about specifying the URL? Could we split them all up into attributes? I think I know what Jeremy would say: this is a simple declarative version. If you’d like to change the default behavior, that’s what JavaScript is for.

But also, should it be there at all if the browser doesn’t support it? Well sure, if you polyfill it:

CodePen Embed Fallback

This polyfill turns the button into a mailto: experience if not supported. That’s pretty clever. I think if I was production-bound, I’d probably only slip the button in when the feature is truly supported.

The post On the Web Share API appeared first on CSS-Tricks.

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

Styling Complex Labels

Css Tricks - Mon, 10/05/2020 - 9:24am

Danielle Romo covers the HTML pattern you need when you have a wordy <label> with fancy styling for an <input type="radio">.

The trick? The ol’ <span class="hidden-visually"> that contains the label that you want to be read, and a <span aria-hidden="true"> with the visual-only content.

CodePen Embed Fallback

I think it’s interesting how often people are landing on this pattern. Have you seen Ethan’s The World-Wide Work? The drop-cap pattern he talks about here lands on essentially the same pattern.

<span aria-hidden="true"> Markup for the visual experience only, where you can (somewhat safely) use markup that would be crap for screen readers. </span> <span class="visually-hidden"> Markup for the read experience only, that you keep very clean on purpose. </span>

That class is like this.

Direct Link to ArticlePermalink

The post Styling Complex Labels appeared first on CSS-Tricks.

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

Parsel: A tiny, permissive CSS selector parser

Css Tricks - Fri, 10/02/2020 - 9:08am

If you’ve ever thought to yourself, gosh, self, I wish I could have an Abstract Syntax Tree (AST) of this CSS selector, Lea has your back.

If you’ve ever thought that same thing for an entire CSS file, that’s what PostCSS is, which has gone v8. PostCSS doesn’t do anything by itself, remember. It just makes an AST out of CSS and gives it a plugin interface so plugins can be written to transform CSS with it. No shade on PostCSS, but it is funny how saying “We use PostCSS” doesn’t mean anything the way “We use Sass” does.

Direct Link to ArticlePermalink

The post Parsel: A tiny, permissive CSS selector parser appeared first on CSS-Tricks.

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

There’s a good reason why experienced devs say “it depends” so often

Css Tricks - Thu, 10/01/2020 - 1:14pm

I feel like Jerod Santo really understood what I was trying to say in Weaved Webs, when I was trying to cover the emerging WordPress (“versus”) Jamstack conversation.

If you asked El Duderino if you should go Jamstack he’d probably tell you, “It’s a complicated case. Lotta ins. Lotta outs. Lotta what-have-yous. Lotta strands to keep in my head, man.”

This conversation is very much not over. Look at what I get to do:

Direct Link to ArticlePermalink

The post There’s a good reason why experienced devs say “it depends” so often appeared first on CSS-Tricks.

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

Syndicate content
©2003 - Present Akamai Design & Development.