Tag: Don’t

Web Frameworks: Why You Don’t Always Need Them

Richard MacManus explaining Daniel Kehoe’s approach to building websites:

There are three key web technologies underpinning Kehoe’s approach:

  • ES6 Modules: JavaScript ES6 can support import modules, which are also supported by browsers.
  • Module CDNs: JavaScript modules can now be downloaded from third-party content delivery networks (CDNs).
  • Custom HTML elements: Developers can now create custom HTML tags, via Web Components.

Using a no build process and only features that are built into browser, and yet that still buys you a pretty powerful setup. You can still use stuff off npm. You can still get templating. You can still build with components. You still get isolation where needed.

I’d say today you’re:

  • Giving up some DX (hot module reloading, JSX, framework doodads)
  • Gaining some DX (can jump into project and just start working)
  • Giving up some performance (no tree shaking, loads of network requests)
  • Widening your hiring pool (more people know core technologies than specific tools)

But it’s not hard to imagine a tomorrow where we give up less and gain more, making the tools we use today less necessary. I’m quite sure we’ll always still find a way to jam more tools into what we’re doing. Hammer something something nail.

Direct Link to ArticlePermalink


The post Web Frameworks: Why You Don’t Always Need Them appeared first on CSS-Tricks.

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

CSS-Tricks

, , , ,

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

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

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

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

Direct Link to ArticlePermalink


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

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

CSS-Tricks

, , , ,
[Top]

“I Don’t Know”

I’ve learned to be more comfortable not knowing. “I don’t know”, comes easier now. “I don’t know anything about that.” It’s okay. It feels good to say.

Whether it’s service workers, Houdini, shadow DOM, web components, HTTP2, CSS grid, “micro-front ends”, AVIF… there are many paths before us. This list doesn’t even broach JavaScript frameworks and libraries. Much of this tech isn’t even novel in 2020—but together act as a clapperboard cueing in me a familiar fear of missing out or imposter syndrome.

How does someone stay current, let alone learn something new? I am reminded of a comment made by Melanie Sumner recently:

Anyone else feel like paying attention to any specific area of development causes the other skills to rust?

To achieve deeper understanding in a topic, one must seclude themselves to a focused path, etching only a tiny arc on the complete circle that is the web. Mastery of a subject comes with it both the elation of achievement and an awareness of the untraveled, much like Matt Might’s The Illustrated Guide to a Ph.D. Piercing or expanding the boundaries of our own spheres of knowledge is exhilarating, yes. But as Melanie observes, it’s a bit like reaching a remote mountain peak only to see more summits stretching out to the horizon. It’s a solitary place, not without reward, but not easily replicated. You must make that next trek from the bottom once more.

The seclusion is as physical as it is mental, given the challenges a global pandemic puts us in. Gone are the meetups, the watercooler moments, the overheard new thing. It was hard enough to ask for help when I could physically tap someone on the shoulder and interrupt their flow. Strangely, it feels more difficult to strike up a call or chat when I’m stuck. Everyone is at the same time a click and a mountain away.

I’ve learned to push through this tendency to seclude and embrace my teammates’ talent. Where I used to enjoy taking a heads-down day to research a problem, I now try to shareout in nearer-to-real-time my findings. The feedback loop is tighter. I’ve adjusted the internal clock that tells me when I am spending too much time on a problem. The team exists to help one another. We’ve set aside time to pair program, mob, and demo. These plans are not without occasional setbacks, however.

Or the time when we got stuck on a bug for 4 hours, only to have fresh eyes glance at the stack trace and find a new path in the span of 15 seconds.

Our more collaborative patterns create a union of skillsets too. We combine arcs of knowledge across the tech we need. We can unblock each other faster, like long-haul truckers tag-teaming a journey. Shared understanding helps us retain context and communicate with less writing. Working more closely on even the mundane has led to change. For example, that engineer that gives me regex tips every time? Where I once bristled, or leaned into their experience, gave way to preemption. “I don’t know how to do that” turned into better and better ideas where to take my first steps. I’d expanded the circumference of my skillset a teensy bit more, journeyed a bit up a new mountain, a guide to help me see the trailhead.

I still walk alone sometimes, and that’s where I can do some of my best work. But I have a better awareness of what I don’t know, and a working realization that my team can go further together than one of us individually. I fret less at the peaks I haven’t explored yet, and am more eager than ever to ask others if they know what’s over there.


The post “I Don’t Know” appeared first on CSS-Tricks.

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

CSS-Tricks

, ,
[Top]

Don’t Wait! Mock the API

Today we have a loose coupling between the front end and the back end of web applications. They are usually developed by separate teams, and keeping those teams and the technology in sync is not easy. To solve part of this problem, we can “fake” the API server that the back end tech would normally create and develop as if the API or endpoints already exist.

The most common term used for creating simulated or “faking” a component is mocking. Mocking allows you to simulate the API without (ideally) changing the front end. There are many ways to achieve mocking, and this is what makes it so scary for most people, at least in my opinion. 

Let’s cover what a good API mocking should look like and how to implement a mocked API into a new or existing application.

Note, the implementation that I am about to show is framework agnostic — so it can be used with any framework or vanilla JavaScript application.

Mirage: The mocking framework

The mocking approach we are going to use is called Mirage, which is somewhat new. I have tested many mocking frameworks and just recently discovered this one, and it’s been a game changer for me.

Mirage is marketed as a front-end-friendly framework that comes with a modern interface. It works in your browser, client-side, by intercepting XMLHttpRequest and Fetch requests.

We will go through creating a simple application with mocked API and cover some common problems along the way.

Mirage setup

Let’s create one of those standard to-do applications to demonstrate mocking. I will be using Vue as my framework of choice but of course, you can use something else since we’re working with a framework-agnostic approach.

So, go ahead and install Mirage in your project:

# Using npm npm i miragejs -D 
 # Using Yarn yarn add miragejs -D

To start using Mirage, we need to setup a “server” (in quotes, because it’s a fake server). Before we jump into the setup, I will cover the folder structure I found works best.

/ ├── public ├── src │   ├── api │   │   └── mock │   │       ├── fixtures │   │       │   └── get-tasks.js │   │       └── index.js │   └── main.js ├── package.json └── package-lock.json

In a mock directory, open up a new index.js file and define your mock server:

// api/mock/index.js import { Server } from 'miragejs'; 
 export default function ({ environment = 'development' } = {}) {   return new Server({     environment, 
     routes() {       // We will add our routes here     },   }); }

The environment argument we’re adding to the function signature is just a convention. We can pass in a different environment as needed.

Now, open your app bootstrap file. In our case, this is he src/main.js file since we are working with Vue. Import your createServer function, and call it in the development environment.

// main.js import createServer from './mock' 
 if (process.env.NODE_ENV === 'development') {     createServer(); }

We’re using the process.env.NODE_ENV environment variable here, which is a common global variable. The conditional allows Mirage to be tree-shaken in production, therefore, it won’t affect your production bundle.

That is all we need to set up Mirage! It’s this sort of ease that makes the DX of Mirage so nice.

Our createServer function is defaulting it to development environment for the sake of making this article simple. In most cases, this will default to test since, in most apps, you’ll call createServer once in development mode but many times in test files.

How it works

Before we make our first request, let’s quickly cover how Mirage works.

Mirage is a client-side mocking framework, meaning all the mocking will happen in the browser, which Mirage does using the Pretender library. Pretender will temporarily replace native XMLHttpRequest and Fetch configurations, intercept all requests, and direct them to a little pretend service that the Mirage hooks onto.

If you crack open DevTools and head into the Network tab, you won’t see any Mirage requests. That’s because the request is intercepted and handled by Mirage (via Pretender in the back end). Mirage logs all requests, which we’ll get to in just a bit.

Let’s make requests!

Let’s create a request to an /api/tasks endpoint that will return a list of tasks that we are going to show in our to-do app. Note that I’m using axios to fetch the data. That’s just my personal preference. Again, Mirage works with native XMLHttpRequest, Fetch, and any other library.

// components/tasks.vue export default {   async created() {     try {       const { data } = await axios.get('/api/tasks'); // Fetch the data       this.tasks = data.tasks;     } catch(e) {       console.error(e);     }   } };

Opening your JavaScript console — there should be an error from Mirage in there:

Mirage: Your app tried to GET '/api/tasks', but there was no route defined to handle this request.

This means Mirage is running, but the router hasn’t been mocked out yet. Let’s solve this by adding that route.

Mocking requests

Inside our mock/index.js file, there is a routes() hook. Route handlers allow us to define which URLs should be handled by the Mirage server.

To define a router handler, we need to add it inside the routes() function.

// mock/index.js export default function ({ environment = 'development' } = {}) {     // ...     routes() {       this.get('/api/tasks', () => ({         tasks: [           { id: 1, text: "Feed the cat" },           { id: 2, text: "Wash the dishes" },           //...         ],       }))     },   }); }

The routes() hook is the way we define our route handlers. Using a this.get() method lets us mock GET requests. The first argument of all request functions is the URL we are handling, and the second argument is a function that responds with some data.

As a note, Mirage accepts any HTTP request type, and each type has the same signature:

this.get('/tasks', (schema, request) => { ... }); this.post('/tasks', (schema, request) => { ... }); this.patch('/tasks/:id', (schema, request) => { ... }); this.put('/tasks/:id', (schema, request) => { ... }); this.del('/tasks/:id', (schema, request) => { ... }); this.options('/tasks', (schema, request) => { ... });

We will discuss the schema and request parameters of the callback function in a moment.

With this, we have successfully mocked our route and we should see inside our console a successful response from Mirage.

Screenshot of a Mirage response in the console showing data for two task objects with IDs 1 and 2.

Working with dynamic data

Trying to add a new to-do in our app won’t be possible because our data in the GET response has hardcoded values. Mirage’s solution to this is that they provide a lightweight data layer that acts as a database. Let’s fix what we have so far.

Like the routes() hook, Mirage defines a seeds() hook. It allows us to create initial data for the server. I’m going to move the GET data to the seeds() hook where I will push it to the Mirage database.

seeds(server) {   server.db.loadData({     tasks: [       { id: 1, text: "Feed the cat" },       { id: 2, text: "Wash the dishes" },     ],   }) },

I moved our static data from the GET method to seeds() hook, where that data is loaded into a faux database. Now, we need to refactor our GET method to return data from that database. This is actually pretty straightforward — the first argument of the callback function of any route() method is the schema.

this.get('/api/tasks', (schema) => {   return schema.db.tasks; })

Now we can add new to-do items to our app by making a POST request:

async addTask() {   const { data } = await axios.post('/api/tasks', { data: this.newTask });   this.tasks.push(data);   this.newTask = {}; },

We mock this route in Mirage by creating a POST /api/tasks route handler:

this.post('/tasks', (schema, request) => {})

Using the second parameter of the callback function, we can see the sent request.

Screenshot of the mocking server request. The requestBody property is highlighted in yellow and contains text data that says Hello CSS-Tricks.

Inside the requestBody property is the data that we sent. That means it’s now available for us to create a new task.

this.post('/api/tasks', (schema, request) => {   // Take the send data from axios.   const task = JSON.parse(request.requestBody).data 
   return schema.db.tasks.insert(task) })

The id of the task will be set by the Mirage’s database by default. Thus, there is no need to keep track of ids and send them with your request — just like a real server.

Dynamic routes? Sure!

The last thing to cover is dynamic routes. They allow us to use a dynamic segment in our URL, which is useful for deleting or updating a single to-do item in our app.

Our delete request should go to /api/tasks/1, /api/tasks/2, and so on. Mirage provides a way for us  to define a dynamic segment in the URL, like this:

this.delete('/api/tasks/:id', (schema, request) => {   // Return the ID from URL.   const id = request.params.id; 
   return schema.db.tasks.remove(id); })

Using a colon (:) in the URL is how we define a dynamic segment in our URL. After the colon, we specify the name of the segment which, in our case, is called id and maps to the ID of a specific to-do item. We can access the value of the segment via the request.params object, where the property name corresponds to the segment name — request.params.id. Then we use the schema to remove an item with that same ID from the Mirage database.

If you’ve noticed, all of my routes so far are prefixed with api/. Writing this over and over can be cumbersome and you may want to make it easier. Mirage offers the namespace property that can help. Inside the routes hook, we can define the namespace property so we don’t have to write that out each time.

routes() {  // Prefix for all routes.  this.namespace = '/api'; 
  this.get('/tasks', () => { ... })  this.delete('/tasks/:id', () => { ... })  this.post('/tasks', () => { ... }) }

OK, let’s integrate this into an existing app

So far, everything we’ve looked at integrates Mirage into a new app. But what about adding Mirage to an existing application? Mirage has you covered so you don’t have to mock your entire API.

The first thing to note is that adding Mirage to an existing application will throw an error if the site makes a request that isn’t handled by Mirage. To avoid this, we can tell Mirage to pass through all unhandled requests.

routes() {   this.get('/tasks', () => { ... })      // Pass through all unhandled requests.   this.passthrough() }

Now we can develop on top of an existing API with Mirage handling only the missing parts of our API.

Mirage can even change the base URL of which it captures the requests. This is useful because, usually, a server won’t live on localhost:3000 but rather on a custom domain.

routes() {  // Set the base route.  this.urlPrefix = 'https://devenv.ourapp.example'; 
  this.get('/tasks', () => { ... }) }

Now, all of our requests will point to the real API server, but Mirage will intercept them like it did when we set it up with a new app. This means that the transition from Mirage to the real API is pretty darn seamless — delete the route from the mock server and things are good to go.

Wrapping up

Over the course of five years, I have used many mocking frameworks, yet I never truly liked any of the solutions out there. That was until recently, when my team was faced with a need for a mocking solution and I found out about Mirage.

Other solutions, like the commonly used JSON-Server, are external processes that need to run alongside the front end. Furthermore, they are often nothing more than an Express server with utility functions on top. The result is that front-end developers like us need to know about middleware, NodeJS, and how servers work… things many of us probably don’t want to handle. Other attempts, like Mockoon, have a complex interface while lacking much-needed features. There’s another group of frameworks that are only used for testing, like the popular SinonJS. Unfortunately, these frameworks can’t be used to mock the regular behavior.

My team managed to create a functioning server that enables us to write front-end code as if we were working with a real back-end. We did it by writing the front-end codebase without any external processes or servers that are needed to run. This is why I love Mirage. It is really simple to set up, yet powerful enough to handle anything that’s thrown at it. You can use it for basic applications that return a static array to full-blown back-end apps alike — regardless of whether it’s a new or existing app.

There’s a lot more to Mirage beyond the implementations we covered here. A working example of what we covered can be found on GitHub. (Fun fact: Mirage also works with GraphQL!) Mirage has well-written documentation that includes a bunch of step-by-step tutorials, so be sure to check it out.


The post Don’t Wait! Mock the API appeared first on CSS-Tricks.

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

CSS-Tricks

, ,
[Top]

Wufoo Cracks the Code for Forms So You Don’t Have To

There was a lot of buzz about forms last week when Jason Grisby pointed to a missing pattern attribute on Chipotle’s order form that could have been used to help-through millions of dollars in orders. Adrian Roselli followed that up with the common mistake of forgetting for and id attributes on form inputs and the potential cost of it.

Forms are hard. And that’s without thinking about more complex features, like building conditional logic into questions, getting into validation, triggering emails on submission, handling inputs on different devices, storing submissions, or integrating with other services, among many, many other things. Forms aren’t just hard, they are downright complicated.

That’s why I’m glad there’s a company like Wufoo that has all of that sorted out. There’s been many a time where I convince myself I can build a form myself only to abandon the idea for an embedded Wufoo form instead.

Why Wufoo? First off, it’s been around forever. They focus on forms and forms alone, so I’m confident they know exactly what they’re doing. I get all the semantic markup I want based on their tried and tested product and adding it to my (or any other) site is as easy as dropping in a snippet.

Plus, Wufoo continues to innovate! They’re releasing new features all the time. Just this past month, they shipped a new Zapier integration that opens up a ton of possibilities, like sending submissions to a Google spreadsheet, firing off submission notifications in Slack, creating Trello cards from submissions, and more. And again, that’s on top of an already stacked featured set that offers everything from multi-page forms and showing and hiding fields conditionally to collecting payments and allowing file uploads over a secure encrypted connection.

You can see where we use Wufoo here on CSS-Tricks to power the contact form. What’s cool about that simple form is we can direct email notifications to specific inboxes based on the contact selection. It even integrates with Mailchimp, so we can offer an option to sign up for our newsletter directly in the contact form.

We also decided to use Wufoo to improve the way we accept guest posts (and you should definitely submit an idea). We used to lean on plain ol’ email and the contact form, but using Wufoo has allowed us to level up so we can collect more details about a post submission upfront and tailor the form based on the type of submission it is.

I’d say Wufoo is great for any type of form. It handles anything you throw at it, easily integrates into any site, and helps prevent costly mistakes that are apparently worth gobs of cash for some companies.

The post Wufoo Cracks the Code for Forms So You Don’t Have To appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Don’t comma-separate :focus-within if you need deep browser support

I really like :focus-within. It’s a super useful selector that allows you to essentially select a parent element when any of its children are in focus.

Say you wanted to reveal some extra stuff when a <div> is hovered…

div:hover {   .extra-stuff {      /* reveal it */   } }

That’s not particularly keyboard-friendly. But if something in .extra-stuff is tab-able anyway (meaning it can be focused), that means you could write it like this to make it a bit more accessible:

div:hover, div:focus-within {   .extra-stuff {      /* reveal it */   } }

That’s nice, but it causes a tricky problem.

Browsers ignore entire selectors if it doesn’t understand any part of them. So, if you’re dealing with a browser that doesn’t support :focus-within then it would ignore the CSS example above, meaning you’ve also lost the :hover state.

Instead:

div:hover {   .extra-stuff {      /* reveal it */   } } div:focus-within {   .extra-stuff {      /* reveal it */   } }

That is safer. But it’s repetitive. If you have a preprocessor like Sass…

@mixin reveal {   .extra-stuff {      transform: translateY(0);   } } div:hover {   @include reveal; } div:focus-within {   @include reveal; }

See the Pen
Mixing for :focus-within without comma-separating
by Chris Coyier (@chriscoyier)
on CodePen.

I’d say it’s a pretty good use-case for having native CSS mixins.

The post Don’t comma-separate :focus-within if you need deep browser support appeared first on CSS-Tricks.

CSS-Tricks

, , , , , ,
[Top]

Which CSS IS AWESOME makes the most sense if you don’t know CSS well?

Peter-Paul posted this question:

Note the interesting caveat: only vote in the poll if you don’t know CSS well.

The winning answer was D! You gotta wonder if the result would have been different if the request for non-CSS experts wasn’t there.

I like to think I know CSS OK, so I didn’t vote. My brain goes like this:

  1. I think he’s asking “by default,” so the answer may assume there’s no other CSS doing anything to that text.
  2. I wish I knew why the box was that particular width, but I guess I’ll just assume it’s a set width.
  3. It’s not B because ellipsis stuff requires extra stuff, and doesn’t work on multiple lines like that — unless we’re talking line clamping, which is even weirder.
  4. It’s not C because that requires hiding overflow which is never really a default — that is, except off the top and left of the browser window, I guess. Or in an iframe.
  5. It’s not D because words just don’t break like that unless you do pretty specific stuff.
  6. A actually makes decent sense. It’s weird to look at, but I’ve been dealing with stuff busting out of containers my whole career. C’est la vie.

Remember, we’ve done a deep dive into CSS IS AWESOME before and how it interestingly captures the weirdness of CSS.

The post Which CSS IS AWESOME makes the most sense if you don’t know CSS well? appeared first on CSS-Tricks.

CSS-Tricks

, , , , , ,
[Top]

Which CSS IS AWESOME makes the most sense if you don’t know CSS well?

Peter-Paul posted this question:

Note the interesting caveat: only vote in the poll if you don’t know CSS well.

The winning answer was D! You gotta wonder if the result would have been different if the request for non-CSS experts wasn’t there.

I like to think I know CSS OK, so I didn’t vote. My brain goes like this:

  1. I think he’s asking “by default,” so the answer may assume there’s no other CSS doing anything to that text.
  2. I wish I knew why the box was that particular width, but I guess I’ll just assume it’s a set width.
  3. It’s not B because ellipsis stuff requires extra stuff, and doesn’t work on multiple lines like that — unless we’re talking line clamping, which is even weirder.
  4. It’s not C because that requires hiding overflow which is never really a default — that is, except off the top and left of the browser window, I guess. Or in an iframe.
  5. It’s not D because words just don’t break like that unless you do pretty specific stuff.
  6. A actually makes decent sense. It’s weird to look at, but I’ve been dealing with stuff busting out of containers my whole career. C’est la vie.

Remember, we’ve done a deep dive into CSS IS AWESOME before and how it interestingly captures the weirdness of CSS.

The post Which CSS IS AWESOME makes the most sense if you don’t know CSS well? appeared first on CSS-Tricks.

CSS-Tricks

, , , , , ,
[Top]

Why I don’t use web components

Here’s an interesting post by Rich Harris where he’s made a list of some of the problems he’s experienced in the past with web components and why he doesn’t use them today:

Given finite resources, time spent on one task means time not spent on another task. Considerable energy has been expended on web components despite a largely indifferent developer population. What could the web have achieved if that energy had been spent elsewhere?

The most convincing part of Rich’s argument for me is where he writes about progressive enhancement and the dependence on polyfills for using web components today. And I’m sure that a lot of folks disagree with many of Rich’s points here, and there’s an awful amount of snark in the comments beneath his post, but it’s certainly an interesting conversation worth digging into. For an opposing perspective, go read the very last paragraph in the last installment of our Web Components Guide, where author Caleb Williams suggests that there’s no need to wait to use web components in projects:

These standards are ready to adopt into our projects today with the appropriate polyfills for legacy browsers and Edge. And while they may not replace your framework of choice, they can be used alongside them to augment you and your organization’s workflows.

But all of this is a good reminder that hey: web components are a thing that we should be able to freely criticize and talk about without being jerks. And I think Rich does that pretty well.

Direct Link to ArticlePermalink

The post Why I don’t use web components appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]

You probably don’t need input type=“number”

Brad Frost wrote about a recent experience with a website that used <input type="number">:

Last week I got a call from my bank regarding a wire transfer I had just scheduled. The customer support guy had me repeat everything back to him because there seemed to be a problem with the information. “Hmmmm, everything you said is right right except the last 3 digits of the account number.”

He had me resubmit the wire transfer form. When I exited the account number field, the corner of my eye noticed the account number change ever so slightly. I quickly refocused into the field and slightly moved my index finger up on my Magic Mouse. It started looking more like a slot machine than an input field!

Brad argues that we then shouldn’t be using <input type="number"> for “account numbers, social security numbers, credit card numbers, confirmation numbers” which makes a bunch of sense to me! Instead we can use the pattern attribute that Chris Ferdinandi looked at a while back in a post all about constraint validation in HTML.

It’s worth mentioning that numeric inputs can be more complex than they appear and that their appearance and behavior vary between browsers. All good things to consider along alongside Brad’s advice when evaluating user experience.

Also:

Direct Link to ArticlePermalink

The post You probably don’t need input type=“number” appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]