Tag: Code

Mondrian Art in CSS From 5 Code Artists

Mondrian is famous for paintings with big thick black lines forming a grid, where each cell is white, red, yellow, or blue. This aesthetic pairs well with the notoriously rectangular web, and that hasn’t gone unnoticed over the years with CSS developers. I saw some Mondrian Art in CSS going around the other day and figured I’d go looking for others I’ve seen over the years and round them up.

Vasilis van Gemert:
What if Mondrian used CSS instead of paint?

Many people have tried to recreate a work of art by Mondriaan with CSS. It seems like a nice and simple exercise: rectangles are easy with CSS, and now with grid, it is easy to recreate most of his works. I tried it as well, and it turned out to be a bit more complicated than I thought. And the results are, well, surprising.

Screenshot of a webpage with a large serif font in various sizes reading What if Mondrian Used CSS instead of Paint? above two paragraphs discussing Mondrian Art in CSS.

Jen Simmons Lab:
Mondrian Art in CSS Grid

I love how Jen went the extra mile with the texture. Like most of these examples, CSS grid is used heavily.

Mondrian Art in CSS Grid from Jen Simmons. Includes rough grungy texture across the entire piece.

Jen Schiffer:
var t;: Piet Mondrian

I started with Mondrian not because he is my favorite artist (he is not), or that his work is very recognizeable (it is), but because I thought it would be a fun (yes) and easy start (lol nope) to this project.

Mondrian Art in CSS randomized 12 times in a 4 by 3 grid of boxes. A bright yellow header is above the grid bearing the site title: var t.

Riley Wong:
Make Your Own Mondrian-Style Painting with Code

There is a 12-step tutorial on GitHub.

Adam Fuhrer:
CSS Mondrian

Generative Piet Mondrian style art using CSS grid.

Screenshot of a full page Mondrian art example. There is a refresh button centered at the bottom of the page.

John Broers:
CSS Mondriaan Grid

An example of Mondrian Art in CSS with a "Generate New" option. The example is a square box with plenty of padding around it on the white background page.

Mondrian Art in CSS From 5 Code Artists originally published on CSS-Tricks. You should get the newsletter and become a supporter.

CSS-Tricks

, , ,

The Many Faces of VS Code in the Browser

VS Code is built from web technologies (HTML, CSS, and JavaScript), but dare I say today it’s mostly used a local app that’s installed on your machine. That’s starting to shift, though, as there has been an absolute explosion of places VS Code is becoming available to use on the web. I’d say it’s kind of a big deal, as VS Code isn’t just some editor; it’s the predominant editor used by web developers. Availability on the web means being able to use it without installing software, which is significant for places, like schools, where managing all that is a pain, and computers, like Chromebooks, where you don’t really install local software at all.

It’s actually kind of confusing all the different places this shows up, so let’s look at the landscape as I see it today.

vscode.dev

It was just a few weeks ago as I write that Microsoft dropped vscode.dev. Chris Dias:

Modern browsers that support the File System Access API (Edge and Chrome today) allow web pages to access the local file system (with your permission). This simple gateway to the local machine quickly opens some interesting scenarios for using VS Code for the Web as a zero-installation local development tool

It’s just Edge and Chrome that have this API right now, but even if you can’t get it, you can still upload files, or perhaps more usefully, open a repo. If it does work, it’s basically… VS Code in the browser. It can open your local folders and it behaves largely just like your local VS Code app does.

I haven’t worked a full day in it or anything, but basic usage seems about the same. There is some very explicit permission-granting you have to do, and keyboard commands are a bit weird as you’re having to fight the browsers keyboard commands. Plus, there is no working terminal.

Other than that it feels about the same. Even stuff like “Find in Project” seems just as fast as local, even on large sites.

GitHub.dev: The whole “Press Period (.) on any GitHub Repo” Thing

You also get VS Code in the browser if you go to github.dev, but it’s not quite wired up the same.

You don’t have the opportunity here to open a local folder. Instead, you can quickly look at a GitHub repo.

But perhaps even more notably, you can make changes, save the files, then use the Source Control panel right there to commit the code or make a pull request.

You’d think vscode.dev and github.dev would merge into one at some point, but who knows.

Oh and hey, thinking of this in reverse, you can open GitHub repos on your locally installed VS Code as well directly (even without cloning it).

There is no terminal or preview in those first two, but there is with GitHub Codespaces.

GitHub Codespaces is also VS Code in the browser, but fancier. For one thing, you’re auth’d into Microsoft-land while using it, meaning it’s running all your VS Code extensions that you run locally. But perhaps a bigger deal is that you get a working terminal. When you spin it up, you see:

Welcome to Codespaces! You are on our default image.

• It includes runtimes and tools for Python, Node.js, Docker, and more. See the full list here: https://aka.ms/ghcs-default-image
• Want to use a custom image instead? Learn more here: https://aka.ms/configure-codespace

🔍 To explore VS Code to its fullest, search using the Command Palette (Cmd/Ctrl + Shift + P or F1).

📝 Edit away, run your app as usual, and we’ll automatically make it available for you to access.

On a typical npm-powered project, you can npm run you scripts and you’ll get a URL running the project as a preview.

This is in the same territory as Gitpod.

Gitpod is a lot like GitHub CodeSpaces in that it’s VS Code in the browser but with a working terminal. That terminal is like a full-on Docker/Linux environment, so you’ve got a lot of power there. It might even be able to mimic your production environment, assuming you’re using all things that Gitpod supports.

It’s also worth noting that Gitpod jacks in “workspaces” that run services. On that demo project above, a MongoDB instance is running on one port, and a preview server is open on another port, which you can see in a mock browser interface there. Being able to preview the project you’re working on is an absolute must and they are handling that elegantly.

Perhaps you’ll remember we used Gitpod in a video we did about DataStax Astra (jumplink) which worked out very nicely.

My (absolute) guess is that Gitpod could be acquired by Microsoft. It seems like Microsoft is headed in this exact direction and getting bought is certainly better than getting steamrolled by the company that makes the core tech that you’re using. You gotta play the “no—this is good! it validates the market! we baked you an awkward cake!” for a while but I can’t imagine it ends well.

This is also a lot like CodeSandbox or Stackblitz.

Straight up, CodeSandbox and Stackblitz also run VS Code in the browser. Or… something that leverages bits and bobs of VS Code at least (a recent episode of Syntax gets into the StackBlitz approach a bit).

You can also install VS Code on your own server.

That’s what Coder’s code-server ia. So, rather than use someone else’s web version of VS Code, you use your own.

You could run VS Code on a local server, but I imagine the big play here is that you run it on live cloud web servers you control. Maybe servers, you know, with your code running on them, so you can use this to literally edit the files on the server. Who needs VIM when you have full-blown VS Code (lolz).

We talked about the school use case, and I imagine this is compelling for that as well, since the school might not even rely on a third-party service, but host it themselves. The iPad/Chromebook use cases are relevant here, too, and perhaps even more so. The docs say “Preserve battery life when you’re on the go; all intensive tasks run on your server,” which I guess means that unlike vscode.dev where tasks like “Find in Project” are (presumably) done on your local machine, they are done by the server (maybe slower, but not slower than a $ 200 laptop?).


There is clearly something in the water with all this. I’m bullish on web-based IDEs. Just look at what’s happening with Figma (kicking ass), which I would argue is one-third due to the product meetings screen designers need with little bloat, one-third due to the simple team and permissions model, and one-third due to the fact that it’s built web-first.


The post The Many Faces of VS Code in the Browser appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , ,
[Top]

What if… you could use Visual Studio Code as the editor of in-browser Developer Tools?

It’s not uncommon for my front-end workflow to go something like this:

  1. Work on thing.
  2. See that thing in an automatically refreshed browser.
  3. See something wrong with that thing.
  4. Inspect and correct the thing in DevTools.
  5. Apply the correct code in my code editor.
  6. See that correct code automatically refreshed in the browser.

I know, it’s not always great. But I’d bet the lint in my pocket you do something similar, at least every now and then.

That’s why I was drawn to the title of Chris Hellman’s post: “What if… you could use Visual Studio Code as the editor of in-browser Developer Tools?”

The idea is that VS Code can be used as the editor for DevTools and we can do it today by enabling it as an experimental feature, alongside Microsoft Edge. So, no, this is not like a prime-time ready universal thing, but watch Chris as he activates the feature, connects VS Code to DevTools, gives DevTools access to write files, then inspects the page of a local URL.

Now, those changes I make in DevTools can be synced back to VS Code, and I have direct access to open and view specific files from DevTools to see my code in context. Any changes I make in DevTools get reflected back in the VS Code files, and any changes I make in VS Code are updated live in the browser. Brilliant.

I’m not sure if this will become a thing beyond Edge but that sort of cross-over work between platforms is something that really excites me.

Direct Link to ArticlePermalink


The post What if… you could use Visual Studio Code as the editor of in-browser Developer Tools? appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , , , , , ,
[Top]

Writing Your Own Code Rules

There comes a time on a project when it’s worth investing in tooling to protect the codebase. I’m not sure how to articulate when, but it’s somewhere after the project has proven to be something long-term and rough edges are starting to show, and before things feel like a complete mess. Avoid premature optimization but avoid, uh, postmature optimization.

Some of this tooling is so easy to implement, it is often done right up-front. I think of Prettier here, a code formatter that keeps your code in shape, usually right as you are coding. There are whole suites of tools you can put in that “as-you-are-coding” bucket, like accessibility linting, compatibility linting, security linting, etc. Webhint bundles a bunch of those together and is probably worth a look.

Then there is tooling that protects your code via more code that you have to write. Tests are the big player here, which can even be set up to run as you code. They are about making sure your code does what it is meant to do, and as such, deliver a hell of a lot of value.

Protecting your code with more code that you write is where I wanted to go with this, not with traditional tests, but with custom linting rules. I thought about it as two different posts about custom linting crossed my desk recently:

I was interested as a user of both ESLint and Stylelint in my main codebase. But fair warning, I found the process for writing custom rules in both of those pretty difficult. You gotta know you way around an Abstract Syntax Tree. It’s nothing like if (rules.find.selector.startsWith("old")) throw("Deprecated selector.") or something easy like that.

I found this all related to an interesting question that came my way:

I work on a development team working on an old project, and we want to get of rid many of our oldest and buggiest CSS selectors. For example, one of us might open a HTML file and see an element with a class name of deprecated-selector, our goal is to have our IDE literally mark it as a linting error and say like “This is a deprecated selector, use .ui-fresh__selector instead”.

The first thing I thought of was a custom Stylelint rules that would look for selectors that your team knows to be deprecated and warn you. But unfortunately, Stylelint is for linting CSS and it sounds like the main issue here is HTML. I know html-inspector had a way to write your own rules, but it’s getting a bit long in the tooth so I don’t know if there is success to be found there or not.


The post Writing Your Own Code Rules appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, ,
[Top]

Web Unleashed is Back! (Use Coupon Code “CSS-Tricks” for 50% Off)

(This is a sponsored post.)

Now in its tenth year (!!!), Web Unleashed is one of the top events for web devs. It’s coming up quick: October 20-22, 2021.

The lineup is amazing. You’ll hear from leaders in the industry, including Ethan Marcotte, Rachel Andrew, Harry Roberts, Addy Osmani, Tracy Lee Ire, Aderinokun, Suz Hinton, Shawn Wang, Jen Looper, and many more.

And don’t forget the coupon code CSS-Tricks as 50% off is a massively good deal! (Here’s where you apply it)

So many hot topics will be covered, including responsive design, optimizing images, open source projects, performance metrics, Gatsby, GraphQL, Applied ML, growing your career, and much much more.

But, seriously folks, take it from someone who has gone to this event a bunch of years… it’s really well done, you’re going to learn a lot, and the price right now is unbeatable. The entire conference clocks in at CA $ 179.16, which is CA $ 89.91 with the CSS-Tricks coupon code. That’s… just go.

Direct Link to ArticlePermalink


The post Web Unleashed is Back! (Use Coupon Code “CSS-Tricks” for 50% Off) appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , ,
[Top]

One Way to Convert Code Indentation

A question:

If you copy a code sample that uses two-space indentation and you want to convert it to four-space indentation, what’s the *fastest* and easiest option?

Matt Stauffer, Twitter

I wrote about doing this in Sublime Text a few years back. It’s not terribly different in VS Code, I don’t think.

But here’s another way: Use CodePen.

Step 1: Copy and paste to CodePen

Say you found some code elsewhere, just copy and paste it in:

Step 2: Adjust code indentation settings

If you already have a CodePen account, you’ve probably already got it set up, so the default is how you like it. But if it’s not yet, adjust it in the Pen Settings area:

Showing the Pen Settings modal open in CodePen over a demo. the settings show code indentation options for spaces and tabs and for indentation width.
The code was 2-spaces as copy/pasted, and now we’re changing that to 4-spaces as a setting.

Step 3: Format the code

You can manually do it here:

You may not have to use that option at all if you save the Pen and have the “Format on Save” option on, as it will automatically happen.

It’ll kick over to that new 4-space preference right quick:


CodePen uses Prettier under the hood to do this. So you could do this anywhere you have access to a working version of Prettier, but it might be easier on CodePen since there’s nothing like editing config or anything to adjust how you want it. Prettier has its own playground as well, which is likely just as easy as CodePen, except that on CodePen you might already have your preferences set up, saving a step.


The post One Way to Convert Code Indentation appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, ,
[Top]

Three Buggy React Code Examples and How to Fix Them

There’s usually more than one way to code a thing in React. And while it’s possible to create the same thing different ways, there may be one or two approaches that technically work “better” than others. I actually run into plenty of examples where the code used to build a React component is technically “correct” but opens up issues that are totally avoidable.

So, let’s look at some of those examples. I’m going to provide three instances of “buggy” React code that technically gets the job done for a particular situation, and ways it can be improved to be more maintainable, resilient, and ultimately functional.

This article assumes some knowledge of React hooks. It isn’t an introduction to hooks—you can find a good introduction from Kingsley Silas on CSS Tricks, or take a look at the React docs to get acquainted with them. We also won’t be looking at any of that exciting new stuff coming up in React 18. Instead, we’re going to look at some subtle problems that won’t completely break your application, but might creep into your codebase and can cause strange or unexpected behavior if you’re not careful.

Buggy code #1: Mutating state and props

It’s a big anti-pattern to mutate state or props in React. Don’t do this!

This is not a revolutionary piece of advice—it’s usually one of the first things you learn if you’re getting started with React. But you might think you can get away with it (because it seems like you can in some cases).

I’m going to show you how bugs might creep into your code if you’re mutating props. Sometimes you’ll want a component that will show a transformed version of some data. Let’s create a parent component that holds a count in state and a button that will increment it. We’ll also make a child component that receives the count via props and shows what the count would look like with 5 added to it.

Here’s a Pen that demonstrates a naïve approach:

This example works. It does what we want it to do: we click the increment button and it adds one to the count. Then the child component is re-rendered to show what the count would look like with 5 added on. We changed the props in the child here and it works fine! Why has everybody been telling us mutating props is so bad?

Well, what if later we refactor the code and need to hold the count in an object? This might happen if we need to store more properties in the same useState hook as our codebase grows larger.

Instead of incrementing the number held in state, we increment the count property of an object held in state. In our child component, we receive the object through props and add to the count property to show what the count would look like if we added 5.

Let’s see how this goes. Try incrementing the state a few times in this pen:

Oh no! Now when we increment the count it seems to add 6 on every click! Why is this happening? The only thing that changed between these two examples is that we used an object instead of a number!

More experienced JavaScript programmers will know that the big difference here is that primitive types such as numbers, booleans and strings are immutable and passed by value, whereas objects are passed by reference.

This means that:

  • If you put a number in a variable, assign another variable to it, then change the second variable, the first variable will not be changed.
  • If you if you put an object in a variable, assign another variable to it, then change the second variable, the first variable will get changed.

When the child component changes a property of the state object, it’s adding 5 to the same object React uses when updating the state. This means that when our increment function fires after a click, React uses the same object after it has been manipulated by our child component, which shows as adding 6 on every click.

The solution

There are multiple ways to avoid these problems. For a situation as simple as this, you could avoid any mutation and express the change in a render function:

function Child({state}){   return <div><p>count + 5 = {state.count + 5} </p></div> }

However, in a more complicated case, you might need to reuse state.count + 5 multiple times or pass the transformed data to multiple children.

One way to do this is to create a copy of the prop in the child, then transform the properties on the cloned data. There’s a couple of different ways to clone objects in JavaScript with various tradeoffs. You can use object literal and spread syntax:

function Child({state}){ const copy = {...state};   return <div><p>count + 5 = {copy.count + 5} </p></div> }

But if there are nested objects, they will still reference the old version. Instead, you could convert the object to JSON then immediately parse it:

JSON.parse(JSON.stringify(myobject)) 

This will work for most simple object types. But if your data uses more exotic types, you might want to use a library. A popular method would be to use lodash’s deepClone. Here’s a Pen that shows a fixed version using object literal and spread syntax to clone the object:

One more option is to use a library like Immutable.js. If you have a rule to only use immutable data structures, you’ll be able to trust that your data won’t get unexpectedly mutated. Here’s one more example using the immutable Map class to represent the state of the counter app:

Buggy code #2: Derived state

Let’s say we have a parent and a child component. They both have useState hooks holding a count. And let’s say the parent passes its state down as prop down to the child, which the child uses to initialize its count.

function Parent(){   const [parentCount,setParentCount] = useState(0);   return <div>     <p>Parent count: {parentCount}</p>     <button onClick={()=>setParentCount(c=>c+1)}>Increment Parent</button>     <Child parentCount={parentCount}/>   </div>; }  function Child({parentCount}){  const [childCount,setChildCount] = useState(parentCount);   return <div>     <p>Child count: {childCount}</p>     <button onClick={()=>setChildCount(c=>c+1)}>Increment Child</button>   </div>; }

What happens to the child’s state when the parent’s state changes, and the child is re-rendered with different props? Will the child state remain the same or will it change to reflect the new count that was passed to it?

We’re dealing with a function, so the child state should get blown away and replaced right? Wrong! The child’s state trumps the new prop from the parent. After the child component’s state is initialized in the first render, it’s completely independent from any props it receives.

React stores component state for each component in the tree and the state only gets blown away when the component is removed. Otherwise, the state won’t be affected by new props.

Using props to initialize state is called “derived state” and it is a bit of an anti-pattern. It removes the benefit of a component having a single source of truth for its data.

Using the key prop

But what if we have a collection of items we want to edit using the same type of child component, and we want the child to hold a draft of the item we’re editing? We’d need to reset the state of the child component each time we switch items from the collection.

Here’s an example: Let’s write an app where we can write a daily list of five thing’s we’re thankful for each day. We’ll use a parent with state initialized as an empty array which we’re going to fill up with five string statements.

Then we’ll have a a child component with a text input to enter our statement.

We’re about to use a criminal level of over-engineering in our tiny app, but it’s to illustrate a pattern you might need in a more complicated project: We’re going to hold the draft state of the text input in the child component.

Lowering the state to the child component can be a performance optimization to prevent the parent re-rendering when the input state changes. Otherwise the parent component will re-render every time there is a change in the text input.

We’ll also pass down an example statement as a default value for each of the five notes we’ll write.

Here’s a buggy way to do this:

// These are going to be our default values for each of the five notes // To give the user an idea of what they might write const ideaList = ["I'm thankful for my friends",                   "I'm thankful for my family",                   "I'm thankful for my health",                   "I'm thankful for my hobbies",                   "I'm thankful for CSS Tricks Articles"]  const maxStatements = 5;  function Parent(){   const [list,setList] = useState([]);      // Handler function for when the statement is completed   // Sets state providing a new array combining the current list and the new item    function onStatementComplete(payload){     setList(list=>[...list,payload]);   }   // Function to reset the list back to an empty array    function reset(){     setList([]);   }   return <div>     <h1>Your thankful list</h1>     <p>A five point list of things you're thankful for:</p>      {/* First we list the statements that have been completed*/}     {list.map((item,index)=>{return <p>Item {index+1}: {item}</p>})}      {/* If the length of the list is under our max statements length, we render      the statement form for the user to enter a new statement.     We grab an example statement from the idealist and pass down the onStatementComplete function.     Note: This implementation won't work as expected*/}     {list.length<maxStatements ?        <StatementForm initialStatement={ideaList[list.length]} onStatementComplete={onStatementComplete}/>       :<button onClick={reset}>Reset</button>     }   </div>; }  // Our child StatementForm component This accepts the example statement for it's initial state and the on complete function function StatementForm({initialStatement,onStatementComplete}){    // We hold the current state of the input, and set the default using initialStatement prop  const [statement,setStatement] = useState(initialStatement);    return <div>     {/*On submit we prevent default and fire the onStatementComplete function received via props*/}     <form onSubmit={(e)=>{e.preventDefault(); onStatementComplete(statement)}}>     <label htmlFor="statement-input">What are you thankful for today?</label><br/>     {/* Our controlled input below*/}     <input id="statement-input" onChange={(e)=>setStatement(e.target.value)} value={statement} type="text"/>     <input type="submit"/>       </form>   </div> }

There’s a problem with this: each time we submit a completed statement, the input incorrectly holds onto the submitted note in the textbox. We want to replace it with an example statement from our list.

Even though we’re passing down a different example string every time, the child remembers the old state and our newer prop is ignored. You could potentially check whether the props have changed on every render in a useEffect, and then reset the state if they have. But that can cause bugs when different parts of your data use the same values and you want to force the child state to reset even though the prop remains the same.

The solution

If you need a child component where the parent needs the ability to reset the child on demand, there is a way to do it: it’s by changing the key prop on the child.

You might have seen this special key prop from when you’re rendering elements based on an array and React throws a warning asking you to provide a key for each element. Changing the key of a child element ensures React creates a brand new version of the element. It’s a way of telling React that you are rendering a conceptually different item using the same component.

Let’s add a key prop to our child component. The value is the index we’re about to fill with our statement:

<StatementForm key={list.length} initialStatement={ideaList[list.length]} onStatementComplte={onStatementComplete}/>

Here’s what this looks like in our list app:

Note the only thing that changed here is that the child component now has a key prop based on the array index we’re about to fill. Yet, the behavior of the component has completely changed.

Now each time we submit and finish writing out statement, the old state in the child component gets thrown away and replaced with the example statement.

Buggy code #3: Stale closure bugs

This is a common issue with React hooks. There’s previously been a CSS-Tricks article about dealing with stale props and states in React’s functional components.

Let’s take a look at a few situations where you might run into trouble. The first crops up is when using useEffect. If we’re doing anything asynchronous inside of useEffect we can get into trouble using old state or props.

Here’s an example. We need to increment a count every second. We set it up on the first render with a useEffect, providing a closure that increments the count as the first argument, and an empty array as the second argument. We’ll give it the empty array as we don’t want React to restart the interval on every render.

function Counter() {    let [count, setCount] = useState(0);    useEffect(() => {     let id = setInterval(() => {       setCount(count + 1);     }, 1000);     return () => clearInterval(id);   },[]);    return <h1>{count}</h1>; }

Oh no! The count gets incremented to 1 but never changes after that! Why is this happening?

It’s to do with two things:

Having a look at the MDN docs on closures, we can see:

A closure is the combination of a function and the lexical environment within which that function was declared. This environment consists of any local variables that were in-scope at the time the closure was created.

The “lexical environment” in which our useEffect closure is declared is inside our Counter React component. The local variable we’re interested is count, which is zero at the time of the declaration (the first render).

The problem is, this closure is never declared again. If the count is zero at the time declaration, it will always be zero. Each time the interval fires, it’s running a function that starts with a count of zero and increments it to 1.

So how might we get the function declared again? This is where the second argument of the useEffect call comes in. We thought we were extremely clever only starting off the interval once by using the empty array, but in doing so we shot ourselves in the foot. If we had left out this argument, the closure inside useEffect would get declared again with a new count every time.

The way I like to think about it is that the useEffect dependency array does two things:

  • It will fire the useEffect function when the dependency changes.
  • It will also redeclare the closure with the updated dependency, keeping the closure safe from stale state or props.

In fact, there’s even a lint rule to keep your useEffect instances safe from stale state and props by making sure you add the right dependencies to the second argument.

But we don’t actually want to reset our interval every time the component gets rendered either. How do we solve this problem then?

The solution

Again, there are multiple solutions to our problem here. Let’s start with the easiest: not using the count state at all and instead passing a function into our setState call:

function Counter() {    let [count, setCount] = useState(0);    useEffect(() => {     let id = setInterval(() => {       setCount(prevCount => prevCount+ 1);     }, 1000);     return () => clearInterval(id);   },[]);    return <h1>{count}</h1>; }

That was easy. Another option is to use the useRef hook like this to keep a mutable reference of the count:

function Counter() {   let [count, setCount] = useState(0);   const countRef = useRef(count)      function updateCount(newCount){     setCount(newCount);     countRef.current = newCount;   }    useEffect(() => {     let id = setInterval(() => {       updateCount(countRef.current + 1);     }, 1000);     return () => clearInterval(id);   },[]);    return <h1>{count}</h1>; }  ReactDOM.render(<Counter/>,document.getElementById("root"))

To go more in depth on using intervals and hooks you can take a look at this article about creating a useInterval in React by Dan Abramov, who is one of the React core team members. He takes a different route where, instead of holding the count in a ref, he places the entire closure in a ref.

To go more in depth on useEffect you can have a look at his post on useEffect.

More stale closure bugs

But stale closures won’t just appear in useEffect. They can also turn up in event handlers and other closures inside your React components. Let’s have a look at a React component with a stale event handler; we’ll create a scroll progress bar that does the following:

  • increases its width along the screen as the user scrolls
  • starts transparent and becomes more and more opaque as the user scrolls
  • provides the user with a button that randomizes the color of the scroll bar

We’re going to leave the progress bar outside of the React tree and update it in the event handler. Here’s our buggy implementation:

<body> <div id="root"></div> <div id="progress"></div> </body>
function Scroller(){    // We'll hold the scroll position in one state   const [scrollPosition, setScrollPosition] = useState(window.scrollY);   // And the current color in another   const [color,setColor] = useState({r:200,g:100,b:100});      // We assign out scroll listener on the first render   useEffect(()=>{    document.addEventListener("scroll",handleScroll);     return ()=>{document.removeEventListener("scroll",handleScroll);}   },[]);      // A function to generate a random color. To make sure the contrast is strong enough   // each value has a minimum value of 100   function onColorChange(){     setColor({r:100+Math.random()*155,g:100+Math.random()*155,b:100+Math.random()*155});   }      // This function gets called on the scroll event   function handleScroll(e){     // First we get the value of how far down we've scrolled     const scrollDistance = document.body.scrollTop || document.documentElement.scrollTop;     // Now we grab the height of the entire document     const documentHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;      // And use these two values to figure out how far down the document we are     const percentAlong =  (scrollDistance / documentHeight);     // And use these two values to figure out how far down the document we are     const progress = document.getElementById("progress");     progress.style.width = `$  {percentAlong*100}%`;     // Here's where our bug is. Resetting the color here will mean the color will always      // be using the original state and never get updated     progress.style.backgroundColor = `rgba($  {color.r},$  {color.g},$  {color.b},$  {percentAlong})`;     setScrollPosition(percentAlong);   }      return <div className="scroller" style={{backgroundColor:`rgb($  {color.r},$  {color.g},$  {color.b})`}}>     <button onClick={onColorChange}>Change color</button>     <span class="percent">{Math.round(scrollPosition* 100)}%</span>   </div> }  ReactDOM.render(<Scroller/>,document.getElementById("root"))

Our bar gets wider and increasingly more opaque as the page scrolls. But if you click the change color button, our randomized colors are not affecting the progress bar. We’re getting this bug because the closure is affected by component state, and this closure is never being re-declared so we only get the original value of the state and no updates.

You can see how setting up closures that call external APIs using React state, or component props might give you grief if you’re not careful.

The solution

Again, there are multiple ways to fix this problem. We could keep the color state in a mutable ref which we could later use in our event handler:

const [color,setColor] = useState({r:200,g:100,b:100}); const colorRef = useRef(color);  function onColorChange(){   const newColor = {r:100+Math.random()*155,g:100+Math.random()*155,b:100+Math.random()*155};   setColor(newColor);   colorRef.current=newColor;   progress.style.backgroundColor = `rgba($  {newColor.r},$  {newColor.g},$  {newColor.b},$  {scrollPosition})`; }

This works well enough but it doesn’t feel ideal. You may need to write code like this if you’re dealing with third-party libraries and you can’t find a way to pull their API into your React tree. But by keeping one of our elements out of the React tree and updating it inside of our event handler, we’re swimming against the tide.

This is a simple fix though, as we’re only dealing with the DOM API. An easy way to refactor this is to include the progress bar in our React tree and render it in JSX allowing it to reference the component’s state. Now we can use the event handling function purely for updating state.

function Scroller(){   const [scrollPosition, setScrollPosition] = useState(window.scrollY);   const [color,setColor] = useState({r:200,g:100,b:100});      useEffect(()=>{    document.addEventListener("scroll",handleScroll);     return ()=>{document.removeEventListener("scroll",handleScroll);}   },[]);      function onColorChange(){     const newColor = {r:100+Math.random()*155,g:100+Math.random()*155,b:100+Math.random()*155};     setColor(newColor);   }    function handleScroll(e){     const scrollDistance = document.body.scrollTop || document.documentElement.scrollTop;     const documentHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;     const percentAlong =  (scrollDistance / documentHeight);     setScrollPosition(percentAlong);   }   return <>     <div class="progress" id="progress"    style={{backgroundColor:`rgba($  {color.r},$  {color.g},$  {color.b},$  {scrollPosition})`,width: `$  {scrollPosition*100}%`}}></div>     <div className="scroller" style={{backgroundColor:`rgb($  {color.r},$  {color.g},$  {color.b})`}}>     <button onClick={onColorChange}>Change color</button>     <span class="percent">{Math.round(scrollPosition * 100)}%</span>   </div>   </> }

That feels better. Not only have we removed the chance for our event handler to get stale, we’ve also converted our progress bar into a self contained component which takes advantage of the declarative nature of React.

Also, for a scroll indicator like this, you might not even need JavaScript — have take a look at the up-and-coming @scroll-timeline CSS function or an approach using a gradient from Chris’ book on the greatest CSS tricks!

Wrapping up

We’ve had a look at three different ways you can create bugs in your React applications and some ways to fix them. It can be easy to look at counter examples which follow a happy path and don’t show subtleties in the APIs that might cause problems.

If you still find yourself needing to build a stronger mental model of what your React code is doing, here’s a list of resources which can help:


The post Three Buggy React Code Examples and How to Fix Them appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , , ,
[Top]

How to Code a Playable Synth Keyboard

With a little knowledge of music theory, we can use regular HTML, CSS and JavaScript — without any libraries or audio samples — to create a simple digital instrument. Let’s put that into practice and explore one method for creating a digital synth that can be played and hosted on the internet.

Here’s what we’re making:

We’ll use the AudioContext API to create our sounds digitally, without resorting to samples. But first, let’s work on the keyboard’s appearance.

The HTML structure

We’re going to support a standard western keyboard where every letter between A and ; corresponds to a playable natural note (the white keys), while the row above can be used for the sharps and flats (the black keys). This means our keyboard covers just over an octave, starting at C₃ and ending at E₄. (For anyone unfamiliar with musical notation, the subscript numbers indicate the octave.)

One useful thing we can do is store the note value in a custom note attribute so it’s easy to access in our JavaScript. I’ll print the letters of the computer keyboard, to help our users understand what to press.

<ul id="keyboard">   <li note="C" class="white">A</li>   <li note="C#" class="black">W</li>   <li note="D" class="white offset">S</li>   <li note="D#" class="black">E</li>   <li note="E" class="white offset">D</li>   <li note="F" class="white">F</li>   <li note="F#" class="black">T</li>   <li note="G" class="white offset">G</li>   <li note="G#" class="black">Y</li>   <li note="A" class="white offset">H</li>   <li note="A#" class="black">U</li>   <li note="B" class="white offset">J</li>   <li note="C2" class="white">K</li>   <li note="C#2" class="black">O</li>   <li note="D2" class="white offset">L</li>   <li note="D#2" class="black">P</li>   <li note="E2" class="white offset">;</li> </ul>

The CSS styling

We’ll begin our CSS with some boilerplate:

html {   box-sizing: border-box; }  *, *:before, *:after {   box-sizing: inherit;   font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,     Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; }  body {   margin: 0; }

Let’s specify CSS variables for some of the colors we’ll be using. Feel free to change them to whatever you prefer!

:root {   --keyboard: hsl(300, 100%, 16%);   --keyboard-shadow: hsla(19, 50%, 66%, 0.2);   --keyboard-border: hsl(20, 91%, 5%);   --black-10: hsla(0, 0%, 0%, 0.1);   --black-20: hsla(0, 0%, 0%, 0.2);   --black-30: hsla(0, 0%, 0%, 0.3);   --black-50: hsla(0, 0%, 0%, 0.5);   --black-60: hsla(0, 0%, 0%, 0.6);   --white-20: hsla(0, 0%, 100%, 0.2);   --white-50: hsla(0, 0%, 100%, 0.5);   --white-80: hsla(0, 0%, 100%, 0.8); }

In particular, changing the --keyboard and --keyboard-border variables will change the end result dramatically.

For styling the keys and the keyboard — especially in the pressed states — I owe a lot of my inspiration to this CodePen by zastrow. First, we specify the CSS shared by all the keys:

.white, .black {   position: relative;   float: left;   display: flex;   justify-content: center;   align-items: flex-end;   padding: 0.5rem 0;   user-select: none;   cursor: pointer; }

Using a specific border radius on the first and last key helps make the design look more organic. Without rounding, the top left and top right corners of keys look a little unnatural. Here’s a final design, minus any extra rounding on the first and last keys.

Let’s add some CSS to improve this.

#keyboard li:first-child {   border-radius: 5px 0 5px 5px; }  #keyboard li:last-child {   border-radius: 0 5px 5px 5px; }

The difference is subtle but effective:

Next, we apply the stylings that differentiate the white and black keys. Notice that the white keys have a z-index of 1 and the black keys have a z-index of 2:

.white {   height: 12.5rem;   width: 3.5rem;   z-index: 1;   border-left: 1px solid hsl(0, 0%, 73%);   border-bottom: 1px solid hsl(0, 0%, 73%);   border-radius: 0 0 5px 5px;   box-shadow: -1px 0 0 var(--white-80) inset, 0 0 5px hsl(0, 0%, 80%) inset,     0 0 3px var(--black-20);   background: linear-gradient(to bottom, hsl(0, 0%, 93%) 0%, white 100%);   color: var(--black-30); }  .black {   height: 8rem;   width: 2rem;   margin: 0 0 0 -1rem;   z-index: 2;   border: 1px solid black;   border-radius: 0 0 3px 3px;   box-shadow: -1px -1px 2px var(--white-20) inset,     0 -5px 2px 3px var(--black-60) inset, 0 2px 4px var(--black-50);   background: linear-gradient(45deg, hsl(0, 0%, 13%) 0%, hsl(0, 0%, 33%) 100%);   color: var(--white-50); }

When a key is pressed, we’ll use JavaScript to add a class of "pressed" to the relevant li element. For now, we can test this by adding the class directly to our HTML elements.

.white.pressed {   border-top: 1px solid hsl(0, 0%, 47%);   border-left: 1px solid hsl(0, 0%, 60%);   border-bottom: 1px solid hsl(0, 0%, 60%);   box-shadow: 2px 0 3px var(--black-10) inset,     -5px 5px 20px var(--black-20) inset, 0 0 3px var(--black-20);   background: linear-gradient(to bottom, white 0%, hsl(0, 0%, 91%) 100%);   outline: none; }  .black.pressed {   box-shadow: -1px -1px 2px var(--white-20) inset,     0 -2px 2px 3px var(--black-60) inset, 0 1px 2px var(--black-50);   background: linear-gradient(     to right,     hsl(0, 0%, 27%) 0%,     hsl(0, 0%, 13%) 100%   );   outline: none; }

Certain white keys need to be moved toward the left so that they sit under the black keys. We give these a class of "offset" in our HTML, so we can keep the CSS simple:

.offset {   margin: 0 0 0 -1rem; }

If you’ve followed the CSS up to this point, you should have something like this:

Finally, we’ll style the keyboard itself:

#keyboard {   height: 15.25rem;   width: 41rem;   margin: 0.5rem auto;   padding: 3rem 0 0 3rem;   position: relative;   border: 1px solid var(--keyboard-border);   border-radius: 1rem;   background-color: var(--keyboard);   box-shadow: 0 0 50px var(--black-50) inset, 0 1px var(--keyboard-shadow) inset,     0 5px 15px var(--black-50); }

We now have a nice-looking CSS keyboard, but it’s not interactive and it doesn’t make any sounds. To do this, we’ll need JavaScript.

Musical JavaScript

To create the sounds for our synth, we don’t want to rely on audio samples — that’d be cheating! Instead, we can use the web’s AudioContext API, which has tools that can help us turn digital waveforms into sounds.

To create a new audio context, we can use:

const audioContext = new (window.AudioContext || window.webkitAudioContext)();

Before using our audioContext it will be helpful to select all our note elements in the HTML. We can use this helper to easily query the elements:

const getElementByNote = (note) =>   note && document.querySelector(`[note="$ {note}"]`);

We can then store the elements in an object, where the key of the object is the key that a user would press on the keyboard to play that note.

const keys = {   A: { element: getElementByNote("C"), note: "C", octaveOffset: 0 },   W: { element: getElementByNote("C#"), note: "C#", octaveOffset: 0 },   S: { element: getElementByNote("D"), note: "D", octaveOffset: 0 },   E: { element: getElementByNote("D#"), note: "D#", octaveOffset: 0 },   D: { element: getElementByNote("E"), note: "E", octaveOffset: 0 },   F: { element: getElementByNote("F"), note: "F", octaveOffset: 0 },   T: { element: getElementByNote("F#"), note: "F#", octaveOffset: 0 },   G: { element: getElementByNote("G"), note: "G", octaveOffset: 0 },   Y: { element: getElementByNote("G#"), note: "G#", octaveOffset: 0 },   H: { element: getElementByNote("A"), note: "A", octaveOffset: 1 },   U: { element: getElementByNote("A#"), note: "A#", octaveOffset: 1 },   J: { element: getElementByNote("B"), note: "B", octaveOffset: 1 },   K: { element: getElementByNote("C2"), note: "C", octaveOffset: 1 },   O: { element: getElementByNote("C#2"), note: "C#", octaveOffset: 1 },   L: { element: getElementByNote("D2"), note: "D", octaveOffset: 1 },   P: { element: getElementByNote("D#2"), note: "D#", octaveOffset: 1 },   semicolon: { element: getElementByNote("E2"), note: "E", octaveOffset: 1 } };

I found it useful to specify the name of the note here, as well as an octaveOffset, which we’ll need when working out the pitch.

We need to supply a pitch in Hz. The equation used to determine pitch is x * 2^(y / 12) where x is the Hz value of a chosen note — usually A₄, which has a pitch of 440Hz — and y is the number of notes above or below that pitch.

That gives us something like this in code:

const getHz = (note = "A", octave = 4) => {   const A4 = 440;   let N = 0;   switch (note) {     default:     case "A":       N = 0;       break;     case "A#":     case "Bb":       N = 1;       break;     case "B":       N = 2;       break;     case "C":       N = 3;       break;     case "C#":     case "Db":       N = 4;       break;     case "D":       N = 5;       break;     case "D#":     case "Eb":       N = 6;       break;     case "E":       N = 7;       break;     case "F":       N = 8;       break;     case "F#":     case "Gb":       N = 9;       break;     case "G":       N = 10;       break;     case "G#":     case "Ab":       N = 11;       break;   }   N += 12 * (octave - 4);   return A4 * Math.pow(2, N / 12); };

Although we’re only using sharps in the rest of our code, I decided to include flats here as well, so this function could easily be re-used in a different context.

For anyone who’s unsure about musical notation, the notes A# and Bb, for example, describe the exact same pitch. We might choose one over another if we’re playing in a particular key, but for our purposes, the difference doesn’t matter.

Playing notes

We’re ready to start playing some notes!

First, we need some way of telling which notes are playing at any given time. Let’s use a Map to do this, as its unique key constraint can help prevent us from triggering the same note multiple times in a single press. Plus, a user can only click one key at a time, so we can store that as a string.

const pressedNotes = new Map(); let clickedKey = "";

We need two functions, one to play a key — which we’ll trigger on keydown or mousedown — and another to stop playing the key — which we’ll trigger on keyup or mouseup.

Each key will be played on its own oscillator with its own gain node (used to control the volume) and its own waveform type (used to determine the timbre of the sound). I’m opting for a "triangle" waveform, but you can use whatever you prefer of "sine", "triangle", "sawtooth" and "square". The spec offers a little more information on these values.

const playKey = (key) => {   if (!keys[key]) {     return;   }    const osc = audioContext.createOscillator();   const noteGainNode = audioContext.createGain();   noteGainNode.connect(audioContext.destination);   noteGainNode.gain.value = 0.5;   osc.connect(noteGainNode);   osc.type = "triangle";    const freq = getHz(keys[key].note, (keys[key].octaveOffset || 0) + 4);    if (Number.isFinite(freq)) {     osc.frequency.value = freq;   }    keys[key].element.classList.add("pressed");   pressedNotes.set(key, osc);   pressedNotes.get(key).start(); };

Our sound could do with some refinement. At the moment, is has a slightly piercing, microwave-buzzer quality to it! But this is enough to get started. We’ll come back and make some tweaks at the end!

Stopping a key is a simpler task. We need to let each note “ring out” for an amount of time after the user lifts their finger (two seconds is about right), as well as make the necessary visual change.

const stopKey = (key) => {   if (!keys[key]) {     return;   }      keys[key].element.classList.remove("pressed");   const osc = pressedNotes.get(key);    if (osc) {     setTimeout(() => {       osc.stop();     }, 2000);      pressedNotes.delete(key);   } };

All that’s left is to add our event listeners:

document.addEventListener("keydown", (e) => {   const eventKey = e.key.toUpperCase();   const key = eventKey === ";" ? "semicolon" : eventKey;      if (!key || pressedNotes.get(key)) {     return;   }   playKey(key); });  document.addEventListener("keyup", (e) => {   const eventKey = e.key.toUpperCase();   const key = eventKey === ";" ? "semicolon" : eventKey;      if (!key) {     return;   }   stopKey(key); });  for (const [key, { element }] of Object.entries(keys)) {   element.addEventListener("mousedown", () => {     playKey(key);     clickedKey = key;   }); }  document.addEventListener("mouseup", () => {   stopKey(clickedKey); });

Note that, while most of our event listeners are added to the HTML document, we can use our keys object to add click listeners to the specific elements we have already queried. We also need to give some special treatment to our highest note, making sure we convert the ";" key into the spelled-out "semicolon" used in our keys object.

We can now play the keys on our synth! There’s just one problem. The sound is still pretty shrill! We might want to knock down the octave of the keyboard by changing the expression that we assign to the freq constant:

const freq = getHz(keys[key].note, (keys[key].octaveOffset || 0) + 3);

You might also be able to hear a “click” at the beginning and end of the sound. We can solve this by quickly fading in and more gradually fading out of each sound.

In music production, we use the term attack to describe how quickly a sound goes from nothing to its maximum volume, and “release” to describe how long it takes for a sound to fade to nothing once it’s no longer played. Another useful concept is decay, the the time taken for sound to go from its peak volume to its sustained volume. Thankfully, our noteGainNode has a gain property with a method called exponentialRampToValueAtTime, which we can use to control attack, release and decay. If we replace our previous playKey function with the following one, we’ll get a much nicer plucky sound:

const playKey = (key) => {   if (!keys[key]) {     return;   }    const osc = audioContext.createOscillator();   const noteGainNode = audioContext.createGain();   noteGainNode.connect(audioContext.destination);    const zeroGain = 0.00001;   const maxGain = 0.5;   const sustainedGain = 0.001;    noteGainNode.gain.value = zeroGain;    const setAttack = () =>     noteGainNode.gain.exponentialRampToValueAtTime(       maxGain,       audioContext.currentTime + 0.01     );   const setDecay = () =>     noteGainNode.gain.exponentialRampToValueAtTime(       sustainedGain,       audioContext.currentTime + 1     );   const setRelease = () =>     noteGainNode.gain.exponentialRampToValueAtTime(       zeroGain,       audioContext.currentTime + 2     );    setAttack();   setDecay();   setRelease();    osc.connect(noteGainNode);   osc.type = "triangle";    const freq = getHz(keys[key].note, (keys[key].octaveOffset || 0) - 1);    if (Number.isFinite(freq)) {     osc.frequency.value = freq;   }    keys[key].element.classList.add("pressed");   pressedNotes.set(key, osc);   pressedNotes.get(key).start(); };

We should have a working, web-ready synth at this point!

The numbers inside our setAttack, setDecay and setRelease functions may seem a bit random, but really they’re just stylistic choices. Try changing them and seeing what happens to the sound. You may end up with something you prefer!

If you’re interested in taking the project further, there are lots of ways you could improve it. Perhaps a volume control, a way to switch between octaves, or a way to choose between waveforms? We could add reverb or a low pass filter. Or perhaps each sound could be made up of multiple oscillators?

For anyone interested in understanding more about how to implement music theory concepts on the web, I recommend looking at the source code of the tonal npm package.


The post How to Code a Playable Synth Keyboard appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , ,
[Top]

A Step-By-Step Process for Turning Designs Into Code

Turning website design files into a combination of HTML, CSS and JavaScript is the bread and butter of many front-end web development jobs, but there’s a part of this work that doesn’t neatly fit in to tutorials on any specific topic. There’s a process of breaking down a design and figuring out how to approach the build that seems to fall under on-the-job training for new front-end developers. It’s not something taught alongside core technologies (no matter where we are learning those technologies—college, bootcamp, or on our own).

In this post, we’ll take a look at how to go from design to code, and why you might want to follow a process like this instead of just diving into code head-first—which, let’s face it, we love to do! The contents of this post are based on my experiences onboarding new developers, the kinds of conversations we’ve had, and the help and feedback I’ve provided in those situations.

One reason the process of moving from design to code is a core professional skill for a front-end developer is that without having some way to dig in and predict how you will approach something, it’s very difficult to provide an estimate for how long it takes to make or what questions you might need answered before you start. Many designs might appear simple at first glance, but quickly become complex once you get into the weeds. I’ve seen this lead to overpromises, which often leads to tighter deadlines, stress and even worse side effects. Suddenly everything takes much longer than we initially thought. Yuck. Let’s see if we can avoid that.

Evaluating a design

As a way to talk about this, let’s use an example design for a “marketing-style” web page and assume we have been asked to implement it. We can also assume this site is created in a context where marketing professionals may come in and edit the content via some content management system (CMS), re-order the sections, replace images, and make style changes. So we need to decide on the components of the page that will be the building blocks used in the CMS.

This gets at another reason that this can be missed in education: often in our own solo projects, we can have static content right there in the HTML, and component parts aren’t going to be Frankenstein-ed together by strangers to form whole new pages and sections. But once you step into more real-world dev situations, things are a lot more dynamic, and we are often working at the layer of “make things that a non-developer can use to make a web page.”

The design for cvshope.com, with header, footer, and various body sections.
Design made by and courtesy of my friend, Dan Ott

Let’s use this website for a clinical trial is example. As we can see there are a lot of familiar design elements. Marketing sites tend to share common patterns:

  • a big hero section
  • product images
  • small separate sections of short-form content emphasizing one thing or another
  • information about the company
  • etc.

On mobile, we can take it as a given that in each section, the left columns will stack on top of the right, and some other fairly typical reflow will happen. Nothing structural will change on mobile. So what we are looking at is the core of the design.

In this example, there is a header, then a lot of distinct sections, and a footer. At a glance, some of the sections look kind of similar—several have a two-column layout, for example. There are button and heading styles that seem to be consistent throughout. As soon as you take a look at something like this, your eye will start to notice repeated patterns like that.

This is where we start making notes. Before we do any coding, let’s understand the ideas contained in the design. These ideas can fall into a few buckets, and we want our final product—the web page itself—to correctly represent all these ideas. Here are the buckets I commonly use:

  1. Layout-level patterns—repeating layout ideas and the overall grid
  2. Element-level patterns—headings, text sizes, fonts, spacing, icons, button sizes
  3. Color palette
  4. Structural ideas—the logical organization of sections, independent from the layout
  5. Everything else—ideas that are only present in one component

Documenting the patterns this way comes in handy for figuring out our CSS approach, but also for choosing what HTML elements to use and starting conversations with the designer or other stakeholders if something is unclear. If you have access to the source files for the design, sections and layers might be labelled in there that give you a good idea what the designer was thinking. This can be helpful when you want to talk about specific sections.

So let’s look at the ideas contained in our example design. We’re going to do several passes through the design, and in all of them, we’re going outside-in, top-to-bottom, and left-to-right to ensure we evaluate every element. In each of the five passes, we’re looking for stuff that goes into just one of the buckets.

We’re unconcerned with getting this list perfect; it can always be changed later—we just want to record our first impressions.

Pass 1: Layout-level ideas

In this design we have a few layout ideas that stand out right off the bat.

  • A header with a horizontal nav section
  • A main content column within the content area—left and right edges align within all sections from header to footer
  • Sections with two columns
  • Sections with a single centered column
  • Sections with a single left-aligned column
  • A footer with three columns
  • Fairly generous padding inside each section
First impressions

We should note any other first impressions we have during this first pass, good or bad. We can never have a first impression twice, and some of our gut reactions and questions can be forgotten if we neglect noting them now. Plus, identifying specific stuff that you like in the design can be nice when we get to talking with the designer. It both helps to celebrate the good stuff and mix it in with other constructive criticism.

Our first impressions might be things like:

  • 👍 The design is clean-looking and readable.
  • 👍 The sections are all titled by questions (good, helps draw reader in and gives each section a clear purpose).
  • 🤨 Question marks are used inconsistently in the titles (possibly just an oversight?).
  • 🙋‍♀️ Sometimes there are very similar font sizes right next to each other (may need to follow up to see if this is intentional because it seems a less slick and professional than the rest of the site).
  • 👍 The logo is nice with that little gradient going on.

Pass 2: Element-level ideas

The section of the CVS Hope page explaining Cyclic Vomiting Syndrome. Regions are highlighted containing different font sizes in side-by-side paragraphs.

Here are things we might notice in this second pass:

  • Primary (blue) and Secondary (white) button styles, plus a “Learn more” button in the header with a little arrow (an expanding menu maybe?)
  • Heading and sub-heading styles
  • Three “body text” sizes (16px, 18px, 20px)
  • A “dark-mode” section where text color is white and the background is dark
  • A consistent presentation of “image & caption” sets
  • Custom bullet points of various kinds
  • Inline links in the text are underlined and, other links, like those in the footer, are not.
  • A repeated card component with an icon on top, and a heading and a list inside the card
  • The logo repeats a few times in different contexts/sizes.
  • The footer contains uppercase headings that don’t appear elsewhere.

Pass 3: Color palette

There is not too much going on in this design color-wise.

  • blue/purple primary color
  • light/dark body text colors
  • light/dark link colors
  • nice gradient under the word “hope” in the logo
  • light gray background color
  • dark navy background color
  • specific red and green “checkmark” and “stop” icon colors

Some design tools let you export the color hex values used in the design file, or even full-on Sass or CSS variable declarations. If you have that option, use it. Otherwise, find your own way to grab those values and name them because those are the foundation for lots of our initial CSS work.

Throughout our CSS and other code, we want to be refer to colors with labels or classes like “primary” and “secondary” that we can reuse throughout the code. This makes it easier to adjust values in the future, and to add themes down the line if we ever need to.

Pass 4: Structural ideas

This is where we might actually name the regions of the page in ways that make sense to us, and identify the hierarchy of the content. We can start to understand the accessibility needs of our implementation by documenting in plain language what we see as the nature and structure of the content in the page. As always, going outside-in, top-to bottom, left-to-right as we make our evaluations.

Focusing on structure helps us figure out the underlying patterns that eventually become our components, and also helps us understand the way we want people who use assistive technology to perceive the content. In turn, that guides us as far as what HTML elements we need to use to write semantic HTML. Semantic HTML speaks to the nature and structure of the content so that it can be perceived correctly by browsers. Browsers use our HTML to create the accessibility tree that assistive tech, like screen readers, uses to present the page. They need a strong outline for that to succeed and semantic HTML provides that solid structure.

This means we need to understand the nature of what’s on the page well enough that we could explain it verbally with no visual support if we had to. From that understanding, we can work backwards to figure out the correct HTML that expresses this understanding via the accessibility tree, which can be inspected in you browser’s developer tools.

Here’s a quick example of the accessibility tree in Chrome if everything on the page is a div, and if elements are correctly chosen to match the nature of the content. Determining the best element choice in a given situation is outside the scope of this post, but suffice it to say that the expressive, non-”generic generic generic” accessibility tree below is entirely created with HTML elements and attributes, and makes the content and its organization much easier for somebody to perceive using assistive technology.

Three screenshots of an accessibility tree. One is made up only of generic containers, the text beside it reads. “Div soup - ignores the nature of the content.” The next is all generic but has a main parent element and one article element with a title, “What is Cyclic Vomiting Syndrome (CVS)?” The text beside it says the article is the odd one out and that we will look closer. The final image is the article element expanded in the accessibility tree, showing that it contains headings, paragraphs, and other semantically appropriate HTML elements. The text beside that one reads “Semantic markup! Stuff knows what it is!”

So, in this fourth pass, here are notes we might make:

  • Top-level structure:
    • Header
    • Main Content
    • Footer

Not so bad for the first top-to-bottom pass. Let’s go a level deeper. We’re still unconcerned with the child inside elements of the sections themselves yet—we want just enough info to label the top level items inside each sections.

  • Within Header there is:
    • Home link
    • Navigation section
  • Within Main Content there is:
    • Hero section
    • Short explainer about the disease itself
    • Explainer about the treatment
    • Intro to the trial
    • Explainer with more details about the trial
    • Statement about who can join the study
    • Call-to-action to participate
    • Short explainer about the company
  • Within Footer there is:
    • Logo
    • Summary Sentence
    • Some lists of links with titles
    • Divider
    • Copyright notice

This pass reveals a few things. First, the Header and Footer sections are pretty shallow and are already revealing raw elements like links and text. Second, the Main section has eight distinct subsections, each with its own topic.

We’re going to do one more pass here and get at some of the deeper details in those sections.

  • Header home link—Woohoo, it’s just a link and we’re done.
  • Header nav—This is an expanding hover nav that needs JavaScript to work correctly. There are probably lots of accessible examples to follow, but still will take more time to develop and test than if we were working with raw links.
  • Hero
    • Title
    • Column 1
      • Subtitle (we missed this in the first element-level pass)
      • Paragraph
      • Primary button link
      • Secondary button link
    • Column 2
      • Hero image
  • Disease Explainer
    • Title
    • Paragraph
    • Unordered list
    • Large text
    • Unordered list
    • Image and caption (figure and figcaption)
    • List of links
  • Treatment Explainer
    • Title
    • Column 1
      • Paragraphs
    • Column 2
      • Image and caption (figure and figcaption)
  • Trial—Intro
    • Title
    • Column 1
      • YouTube Video Player
    • Column 2
      • Paragraphs
  • Trial—More Details
    • Title
    • Subtitle
    • Cards (with Icon, Title, and List)
  • Who Can Join” statement
    • Title
    • Column 1
      • Paragraph
      • Unordered list
    • Column 2
      • Paragraph
      • Unordered list
  • Call-to-Action
    • Title
    • Paragraph
    • Secondary button link
  • About the Company
    • Title
    • Paragraph

Yowza, that got long fast! But now we understand pretty well the kinds of things we need to build, and what parts might be tricky. We also see that there may be some helper components to be built that aren’t quite represented by any one of these sections, for example, a two-column layout component that stacks to one column on mobile and has a title on top, or a generic “section container” component that takes a background and foreground color and provides the right styles plus standardized internal padding.

Incidentally, with this breakdown we’ve done a pretty good job expressing the final accessibility tree we want our HTML to create, so we are well on our way to having the implementation be a smooth experience without a lot of re-work to get accessibility right.

Pass 5: Everything else

What are some other ideas contained in this design, things that stick out, or challenges we notice? Maybe not much, but this is kind of the other side of the “first impressions” notes. Now our heads are filled with context for what it is in the design.

If something stands out now, especially if it’s a question about how something works, capture it. An example is, “Hmm, what is the ‘Learn More’ link in the nav supposed to do?” The answer might be: “It’s a list of links to each section that open when you hover there.” Every now and then, a designer expects that this kind of thing is already implied in the design, even if it is not explicitly documented, and it only comes up at the design review stage after that thing is developed—which is often too late to correct without affecting dates and deadlines.

We should also now look deeply and identify any hidden “glue work”— things like getting our styles in order, handling mobile, configuring the CMS, adding and testing authoring options and arrangements for our building blocks, and adding automated tests. Stuff like that.

At this point, we are ready to nail down exactly what components can be created in the CMS. Maybe we already have some of the basic setup done in the current system from past work. Whatever the case, we have enough to draw on to offer a decent estimate of the work needed, grouped into categories. For example, we might categorize components that:

  • are already 100% ready (no dev time needed),
  • exist but need tweaks for this new purpose (predictable dev time needed),
  • are totally new, but the path is obvious and safe (predictable dev time needed),
  • are totally new and need some research to implement. Or the design is unclear, or something about it gives you the heebie-jeebies and you need to have discussions with stakeholders. The earlier you can spot this, the better. Talk it over with whoever is running the project.

Now we have enough information to make a reasonable estimate. And more to the point, we’ve reduced the total time the project will take, and limited the trouble we might have along the way, because we’ve gained several advantages from planning it out.

The advantages of having a process

The exact steps we take and what order they are completed in is not the main point. What matters most is understanding the kind of information you need to gather when starting on a project. You might have your own ideas about how the work is done and in what order, whatever works for you is great.

Here are the advantages I’ve realized when assessing a design with a process in mind, compared to just kinda diving in, “getting stuff working,” and handling things as they come up.

You do a little extra discovery

As much as we’d like every project to arrive fully formed and perfectly ready to start, in reality, designs often contain assumptions that might be impractical to implement, or contradict something else we care about, like accessibility. In that case, you can assess the whole thing up front and get the conversations started with people who can resolve those issues early in the process. This can happen while you dive into the pieces that are ready to code, and will stop you from bumping into these roadblocks later when you are about to build that part of it. Flagging concerns early is definitely appreciated by the people who need to solve them.

You can be helped by others

Without a plan, it can be difficult to understand how far along you are in completing the project, as well as knowing if you need help meeting a deadline. Even if you do need help and are able to ask for it, it’s tough to use extra helping hands effectively without the work being broken out in to separate little chunks that be easily divided. When you have a plan that makes sense, you can quickly delegate certain tickets, knowing that the jigsaw pieces will fit together in the end.

It’s easy (and common) for a new developer to think think that huge workloads and working around the clock is a good thing. But as you mature in the role, you’ll see that having a deep understanding of the whole picture of a project, or even a single ticket, is more valuable, while creating a better impression that you are “on top of things.” Recognizing early that a timeline doesn’t look right gives you options about how to address it in ways other than trying to be a hero and throwing some weekends at it.

Component architecture flows better

Architectural decisions are the worst for me. Naming components, figuring out where stuff should live, which components need to talk to each other, where to break stuff up into smaller components. A lot of those choices only make sense when we look at the bigger picture and think about all various ways that certain elements might be used by visitors and content creators. And a lot of these choices are marginal—choosing the “best” option between two acceptable solutions can be a huge time suck or completely subjective.

Have a process helps with that because you are going to get all, or most, of the information you need about the designs before digging deeply into the development work. For me, figuring out what pieces I need to make, and figuring out the best possible code to make those pieces, are two different things. Sometimes what I need is not the thing that comes most naturally from the code. And sometimes, after learning a bit about what is needed, I can avoid time spent bikeshedding marginal decisions because it’s more clear which decisions truly don’t matter.

You still learn new things as you write the code, of course, but you’re now better prepared to handle those things when they pop up. You even have a good idea about the kinds of that might present themselves.

Styles make more sense

As you plan the work, you can truly figure out which styles are global, which are section-specific, which are or component-specific, and which are one-off exceptions. If you don’t already have a system you like for this, Andy Bell’s Cube CSS pairs very well with the kind of breakdown I’m talking about. Here’s a video of Andy working through an example with Chris Coyier that you can check out for more about this approach.

Accessibility starts early in the process

This one is huge for me. By really understanding the ideas contained in the design, you will have an easier time picking semantic HTML elements and finding appropriate accessible patterns to build out what you see there. Accessibility can work its way into the daily work you do, rather than an afterthought or extra burden. Our perspective becomes that high-quality front-end code correctly expresses the nature and structure of its content to all users, and accessibility is how we measure that.

After a pretty short period, you’ll see how often designs conform to one known pattern or another, and the flow of breaking something down into known patterns to implement will speed up dramatically. Carie Fisher nicely sums up ideas related to this “Accessibility-first” approach.

Wrapping up

Like I said at the start, a lot of this falls under on-the-job training, the “oral tradition” of web development. It’s the kind of stuff you might hear from a senior developer on your team as you’re getting started in your first front-end role. I’m sure lots of people would have different priorities than I do and recommend a slightly different process. I also know for sure that a lot of folks out there work in situations without a solid process in place, and no one senior to consult.

If you are in that situation, or not yet in your first role, I hope this gives you a baseline you can relate to when you think about how to do the job. Ideally the job is not just diving in and putting stuff in divs until things look “right” but that is often our mode of operation. We are eager to make progress and see results.

I’m very grateful that I did have somebody working with me at my first development job who showed me how to split up pieces of a design and estimate work for large, long-term projects. That’s what inspired me to start thinking about this and—as I began supervising other developers and teams—thinking about how I wanted to adapt the process and make it my own. I also realized it wasn’t something I’d noticed people talking much about when teaching technical skills about using a particular language. So thanks, Nate!


Thanks also to Drew Clements and Nerando Johnson for providing early feedback on this post. You are the best.


The post A Step-By-Step Process for Turning Designs Into Code appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , , ,
[Top]

Useful and Useless Code Comments

Jim Nielsen:

If somebody says a comment isn’t adding any value, I would ask: to whom?

Personally, I’ve never liked the advice that writing obvious comments is bad practice—probably because I write obvious comments all the time.

Jim showed off some examples of “code comments that are at the same level of fidelity as the code itself.” Those are the hardest calls with code comments.

// this function adds two numbers function add(a, b) {   return a + b; }

Easy to point at that and call it not useful. I tend not to leave this type of comment, but it’s fair play for Jim to question that. Comments can be used for a wide swath of people whom may at some point interact with that code, so why gate-keep it?

[…] comments can serve a very different purpose when they’re being read vs. when they’re being written. Those are almost two different kinds of activities.

I’d add they serve a different purpose when re-visiting old code vs actively working. Also different when you’re trying to code review versus directly contribute.

Direct Link to ArticlePermalink


The post Useful and Useless Code Comments appeared first on CSS-Tricks.

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

CSS-Tricks

, , ,
[Top]