Tag: Code

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

, ,

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]

VS Code Extensions for HTML

Let’s look at some extensions for VS Code that make writing and editing HTML (and languages that are basically HTML with extra powers) better. You may not like all of them. Maybe some of them don’t appeal to you, solve a problem you don’t have, or feel like more clutter than you need. That’s OK. These are just a handful that I’ve tried and liked to some degree.

I’d start with Emmet here, even thought it’s not technically an extension1 for VS Code. It’s built right in. You should know about it though because it’s very useful. It does “HTML Expansions” like this, which I use pretty much every day of my life:

HTML End Tag Labels

I heard about this one from Stefan Judis who blogged about it the other day and inspired this post idea.

The whole idea is that rather than you leaving comments in your HTML to indicate what HTML element it is closing (a somewhat common practice, especially for partials that close elements that might not be opened in the same document).

<div class="main">   </div> <!-- / div.main -->  <?php /* / div.main */ ?> <?php /* Sometimes I'd do it in a server side language so it didn't go over the wire. */ ?>

This extension shows you UI about what HTML is being closed:

Auto Close Tag

As soon as you type the > in an HTML element, like the last bracket in <div>, the closing tag is automatically created for you.

It can be configured to only auto close after you’ve typed the </ to indicate you’re about to close a tag, which is a default in Sublime Text 3. Speaking of which, if you install the Sublime Text Keymap, you’d get that automatically, plus a handful of other fancy key commands.

There is also Close HTML/XML tag, but it only works via key command. With Auto Close Tag you can configure it either way, and it has far more installs for whatever reason.

Highlight Matching Tag

Here’s the GIF from their docs:

I was going to do my own video, but I discovered that even if I have this extension off, something else in my VS Code is highlighting matching tags anyway. I’m not entirely sure what it is, which leads me to believe it might be a built-in feature now.

What I see without this extension on: a border around the matching tags.

Not specific to HTML, but if like this sort of help with matching things, you might give Bracket Pair Colorizer 2 a try, which can be quite nice for CSS and JavaScript.

Auto Rename Tag

I find this one quite useful!

I believe this functionality is actually built into the canonical Emmet, but again, VS Code doesn’t use canonical Emmet so this feature isn’t there, hence the need for this extra plugin.

Better Comments

I leave code comments fairly liberally, especially when dev’ing out new things. A convention I like is when a comment is prefixed (e.g. TODO) that it is extra important and needs attention. Better Comments allows those to look visually different.

Code Spell Checker

There is no spell-checking in VS code. I don’t love that. To me this plugin is a must-have, especially for HTML, because HTML typically has content in it, like words, that should be spelled correctly. And just like a linter, this plugin gives you squiggles when something is wrong and a menu to attempt to fix it.

Indent Rainbow

Bask in this glorious rainbow created by deepening indents:

The point is that it gives you some visual cues to what level you’re currently looking/working at. In that sense it’s kinda like the Highlight Matching Tag, but I like them both honestly. It’s most useful when you need to scroll up or down to find where the matching tag is.

Prettier

Prettier does work on HTML, but I’d almost call it a smidge controversial. For example, it breaks HTML attributes onto single lines which feels a lot like a JSX thing but less common to see in raw HTML. But sometimes there are literal side effects. Like if you type <ul><li></li><li></li></ul> on purpose like that (no whitespace) because you’re going to set all the list items inline, Prettier will break them onto their own lines, inserting whitespace, and changing the layout of what you intend. You can always fix it with a comment for Prettier to leave it alone (e.g. {/* prettier-ignore */}), but I could see it rubbing people the wrong way. There are even settings for it under HTML Whitespace Sensitivity, but it could never be perfect.

I actually got Prettier for HTML working just for this blog post so I think I’ll keep it for a while and see if I like it. I already know I like Prettier for JSX. I’m generally for as much autoformatting as possible.

Snippet

I gotta imagine there are lots of snippet plugins, but this is the only one I’ve tried and it works fine. I like how you make snippets right from existing files.

Tabnine

I heard about this one from Kyle Simpson who I think was doing some paid consulting with them or something. The point of it is that it does fancy AI-powered autocomplete suggestions, even in HTML. Check out it guessing at some attributes:

This looks like a pretty commercial product with features that push you toward paid plans for teams. I don’t really feel like getting all into that; it was just interesting to see a tool like this work with HTML.

axe Accessibility Linter

This lints your HTML for accessibility problems right in the editor. There are a bunch of rules it checks for.


  1. Did you know even though VS Code has Emmet baked right in, there is no communication between Emmet’s creator and the VS Code team? I’ve tried to facilitate that connection in the past, but failed. Point being: Emmet in VS Code would probably be better if it wasn’t just jacked in but integrated from the official packages. Emmet has new things that VS Code could use, like expansion previews.

The post VS Code Extensions for HTML appeared first on CSS-Tricks.

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

CSS-Tricks

, ,
[Top]

Code blocks, but better

Pedro Duarte made a wishlist for styled code blocks in blog posts and documentation, then hand-rolls a perfect solution for that wishlist. For example, a feature to be able to highlight certain lines or words within the code block. The line highlighter is unique in that it only syntax highlights the highlighted lines, leaving the rest gray, which is a neat way to draw focus. And the word highlighter works via a RegEx. Pedro notes this isn’t a tutorial, it’s just a showcase of all the features that were stitched together using an existing combination of custom code and existing libraries. It’s pretty specific to React + Next.js + MDX, but apparently the core of it is based on rehype, which is new to me.

The results are pretty darn nice, modern-looking code blocks if you ask me! At the same time, I think it’s equally notable what’s not there as opposed to what is. I’ve seen (and tried) really featured-packed code blocks in the past, with features like a copy to clipboard button, a view raw code button, and export to whatever services. Pedro’s code blocks don’t even have an option to show the language in use.

Everybody’s wishlist is different. One thing that isn’t on Pedro’s wishlist is server-side rendering, but you can see on the blog post itself that it totally works with that (it’s presumably just Next.js at work). I’m pretty envious of that. Even though we’re ultimately both using Prism.js as the syntax highlighter, I’m only using it client-side. It occurs to me now that I could perhaps pull all this off in a Cloudflare Worker by using the HTMLRewriter — meaning it would essentially look like it’s done server-side and I could rip off the client-side copy of Prism. Maybe even more ideally, though, is that I’d do it as a WordPress plugin. Basically a PHP port of Prism, which seems like a tall order.

My wishlist for code block plugin…

  • Syntax highlighting (both on the rendered site and while authoring)
  • Server-side rendered <span class="token-foo"> stuff for syntax highlighting
  • Works nicely with the native WordPress block editor code blocks (```). For example, pasting in a code block auto-detects and uses the correct block. Easy to convert code to and from this kind of block.
  • Optional line highlighter
  • Optional line numbers
  • Optional word highlighter
  • Optional language display (and the ability to override that label)
  • Copy and paste very cleanly
  • No need to escape code while authoring
  • Freedom to style however on the front end (for modes, themes, custom scrollbars, etc). Styling code blocks has a million things to consider, so smart defaults should probably come with the plugin, but easy to override.
  • Stretch goal: can it somehow help with inline code as well?

Direct Link to ArticlePermalink


The post Code blocks, but better appeared first on CSS-Tricks.

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

CSS-Tricks

, ,
[Top]

To $ or Not to $: Displaying Terminal Code Snippets

It’s very popular to put a $ on lines that are intended to be a command in code documentation that involves the terminal (i.e. the command line).

Like this:

$  brew install somepackage

The point of that is that it mimics the prompt that you (may) see on your command line. Here’s mine:

So the dollar sign ($ ) is a little technique that people use to indicate this line of code is supposed to be run on the command line.

Minor trouble

The trouble with that is that I (and I’ll wager most other people too) will copy and paste commands like that from that documentation.

If I run that command above in my terminal exactly as it’s written…

…it doesn’t work. $ is not a command. How do you deal with this? You just have to know. You just need to have had this problem before and somehow learned that what the documentation is actually telling you is to run the command brew install somepackage (without the dollar sign) at the command line.

I say minor trouble as there are all sorts of stuff like this in every job in the world. When I put something like font-size: 2.2rem in a blog post, I don’t also say, “Put that declaration in a ruleset in a CSS file that your HTML file links to.” You just have to know those those things.

Fixing it with CSS

The fact that it’s only minor trouble and that tech is laden with things you just need to know doesn’t mean that we can’t try to fix this and do a little better.

The idea for this post came from this tweet that got way more likes than I thought it would:

To expand on that, I’d expect you’re probably marking up your docs something like:

<p>Install package like:</p>  <pre><code class="command">brew install package</code></pre>

Now you can insert the $ as a pseudo-element rather than as actual text:

code.command::before {   content: "$  "; }

Now you aren’t just saving yourself a character in the HTML, the $ cannot be selected, because that’s how pseudo-elements work. So now you’re now a bit better in the UX department. Even if the user double-clicks the line or tries to select all of it, they won’t get the $ screwing up the copy-paste.

Hopefully they aren’t equally frustrated by not being able to copy the $ . 😬

So, anyway, something like this incredible design by me:

Fixing it with text

A lot of documentation for code-things are on a public git repo place like GitHub. You don’t have access to CSS to style what GitHub looks like, so while there is trickery available, you can’t just plop a line of CSS in there to style things.

We might have to (gasp) use our words:

<p>   Install the package by entering this    command at your terminal: </p>  <kbd class="command">brew install package</kbd>

Other thoughts

  • You probably wouldn’t bother syntax highlighting it at all. I don’t think I’ve ever seen a terminal that syntax highlights commands as you enter them.
  • Eric Meyer suggested the <kbd> element which is the Keyboard Input element. I like that. I’ve long used <code> but I think <kbd> is more appropriate here.
  • Tim Chase suggested using a <span> and including the prompt in the HTML so you can style it uniquely if you want, including making it not selectable with user-select: none;.
  • Justin Searls has a dotfiles trick where if you accidently copy/paste the $ , it just ignores it and runs everything after it.
  • Jackson Bates suggests being very careful about what you copy and paste to a terminal.
  • I learned that $ is also a way of denoting “unprivileged” commands while # is for root commands. Part of that reason is that if you copy-paste a root command, it won’t run as it will be recognized as a comment.

The post To $ or Not to $ : Displaying Terminal Code Snippets appeared first on CSS-Tricks.

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

CSS-Tricks

, , ,
[Top]

Creating an Editable Textarea That Supports Syntax-Highlighted Code

When I was working on a project that needed an editor component for source code, I really wanted a way to have that editor highlight the syntax its typed. There are projects like this, like CodeMirror, Ace, and Monaco, but they are all heavy-weight, full-featured editors, not just editable textareas with syntax highlighting like I wanted.

It took a little finagling, but I wound up making something that does the job and wanted to share how I did it, because it involves integrating a popular syntax highlighting library with HTML’s editing capabilities, as well as a few interesting edge cases to take into consideration.

Go ahead and give it a spin as we dig in!

The problem

First, I tried using the contenteditable attribute on a div. I typed some source code into the div and ran it through Prism.js, a popular syntax highlighter, on onkeyup via JavaScript. Seems like a decent idea, right? We have an element that can be edited on the front end, and Prism.js applies its syntax styling to what’s typed in the element.

Chris covers how to use Prism.js in this video.

But that was a no-go. Each time the content in the element changes, the DOM is manipulated and the user’s cursor is pushed back to the start of the code, meaning the source code appears backwards, with the last characters at the start, and the first characters at the end.

White monospaced text on a black background that does not spell a coherent word.
Backwards code: not very useful

Next, I tried about using a <textarea> but that also didn’t work, as textareas can only contain plain text. In other words, we’re unable to style the content that’s entered. A textarea seems to be the only way to edit the text without unwanted bugs — it just doesn’t let Prism.js do its thing.

Prism.js works a lot better when the source code is wrapped in a typical <pre><code> tag combo — it’s only missing the editable part of the equation.

So, neither seems to work by themselves. But, I thought, why not both?

The solution

I added both a syntax-highlighted <pre><code> and a textarea to the page, and made the innerText content of <pre><code> change onkeyup, using a JavaScript function. I also added an aria-hidden attribute to the <pre><code> result so that screen readers would only read what is entered into the <textarea> instead of being read aloud twice.

<textarea id="editing" onkeyup="update(this.value);"></textarea>  <pre id="highlighting" aria-hidden="true">   <code class="language-html" id="highlighting-content"></code> </pre>
function update(text) {   let result_element = document.querySelector("#highlighting-content");   // Update code   result_element.innerText = text;   // Syntax Highlight   Prism.highlightElement(result_element); }
The HTML for a link element pointed to CSS-Tricks is in black monospace on a white background above the same HTML link markup, but syntax-highlighted on a black background.
Now it’s editable and highlighted!

Now, when the textarea is edited — as in, a pressed key on the keyboard comes back up — the syntax-highlighted code changes. There are a few bugs we’ll get to, but I want to focus first on making it look like you are directly editing the syntax-highlighted element, rather than a separate textarea.

Making it “feel” like a code editor

The idea is to visibly merge the elements together so it looks like we’re interacting with one element when there are actually two elements at work. We can add some CSS that basically allows the <textarea> and the <pre><code> elements to be sized and spaced consistently.

#editing, #highlighting {   /* Both elements need the same text and space styling so they are directly on top of each other */   margin: 10px;   padding: 10px;   border: 0;   width: calc(100% - 32px);   height: 150px; }  #editing, #highlighting, #highlighting * {   /* Also add text styles to highlighting tokens */   font-size: 15pt;   font-family: monospace;   line-height: 20pt; }

Then we want to position them right on top of each other:

#editing, #highlighting {   position: absolute;   top: 0;   left: 0; }

From there, z-index allows the textarea to stack in front the highlighted result:

/* Move the textarea in front of the result */ #editing {   z-index: 1; }  #highlighting {   z-index: 0; }

If we stop here, we’ll see our first bug. It doesn’t look like Prism.js is highlighting the syntax, but that is only because the textarea is covering up the result.

Where has the highlighting gone? (Clue: It’s hiding in the background.)

We can fix this with CSS! We’ll make the <textarea> completely transparent except the caret (cursor):

/* Make textarea almost completely transparent */ #editing {   color: transparent;   background: transparent;   caret-color: white; /* Or choose your favorite color */ }

Ah, much better!

HTML markup for a link element pointed to CSS tricks in a syntax-highlighted monospace font on a black background.
Where will this link take you? You decide.

More fixing!

Once I got this far, I played around with the editor a bit and was able to find a few more things that needed fixing. The good thing is that all of the issues are quite easy to fix using JavaScript, CSS, or even HTML.

Remove native spell checking

We’re making a code editor, and code has lots of words and attributes that a browser’s native spell checker will think are misspellings.

Showing the basic HTML markup for a link with syntax highlighting on a black background, where the href attribute is underlined in red.

Spell checking isn’t a bad thing; it’s just unhelpful in this situation. Is something marked incorrect because it is incorrectly spelled or because the code is invalid? It’s tough to tell. To fix this, all we need is to set the spellcheck attribute on the <textarea> to false:

<textarea id="editing" spellcheck="false" ...>

Handling new lines

Turns out that innerText doesn’t support newlines (n).

White monospace text on a black background. The first line says "Hello, World" and the second line says "World" and is highlight in blue.
Even though “World!” should be on a new line, the syntax highlighted section displays it on the same line.

The update function needs to be edited. Instead of using innerText, we can replace the open bracket character (<) with &lt;. This prevents new HTML tags from being created, allowing the actual source code displays instead of the browser attempting to render the code.

result_element.innerHTML = text.replace(new RegExp("<", "g"), "<"); /* Global RegExp */
Showing the basic HTML document boilerplate with syntax highlighting on a black background. The body element contains the markup yo a paragraph that contains a link that says "CSS-Tricks is brilliant!"

Scrolling and resizing

Here’s another thing: the highlighted code cannot scroll while the editing is taking place. And when the textarea is scrolled, the highlighted code does not scroll with it.

First, let’s make sure that both the textarea and result support scrolling:

/* Can be scrolled */ #editing, #highlighting {   overflow: auto; }

Then, to make sure that the result scrolls with the textarea, we’ll update the HTML and JavaScript like this:

<textarea id="editing" onkeyup="update(this.value); sync_scroll(this);" onscroll="sync_scroll(this);"></textarea>
function sync_scroll(element) {   /* Scroll result to scroll coords of event - sync with textarea */   let result_element = document.querySelector("#highlighting");   // Get and set x and y   result_element.scrollTop = element.scrollTop;   result_element.scrollLeft = element.scrollLeft; }

Some browsers also allow a textarea to be resized, but this means that the textarea and result could become different sizes. Can CSS fix this? Of course it can. We’ll simply disable resizing:

/* No resize on textarea */ #editing {   resize: none; }

Indenting lines

One of the trickier things to adjust is how to handle line indentations in the result. The way the editor is currently set up, indenting lines with spaces works fine. But, if you’re more into tabs than spaces, you may have noticed that those aren’t working as expected.

JavaScript can be used to make the Tab key properly work. I have added comments to make it clear what is happening in the function.

<textarea ... onkeydown="check_tab(this, event);"></textarea>
function check_tab(element, event) {   let code = element.value;   if(event.key == "Tab") {     /* Tab key pressed */     event.preventDefault(); // stop normal     let before_tab = code.slice(0, element.selectionStart); // text before tab     let after_tab = code.slice(element.selectionEnd, element.value.length); // text after tab     let cursor_pos = element.selectionEnd + 2; // where cursor moves after tab - 2 for 2 spaces     element.value = before_tab + "  " + after_tab; // add tab char - 2 spaces     // move cursor     element.selectionStart = cursor_pos;     element.selectionEnd = cursor_pos;   } }

The final result

Not too crazy, right? All we have are <textarea>, <pre> and <code> elements in the HTML, a new lines of CSS that stack them together, and a syntax highlighting library to format what’s entered. And what I like best about this is that we’re working with normal, semantic HTML elements, leveraging native attributes to get the behavior we want, leaning on CSS to create the illusion that we’re only interacting with one element, then reaching for JavaScript to solve some edge cases.

While I used Prism.js for syntax highlighting, this technique will work with others. It would even work with a syntax highlighter you create yourself, if you want it to. I hope this becomes useful, and can be used in many places, whether it’s a WYSIWYG editor for a CMS, or even a forms where the ability to enter source code is a requirement like a front-end job application or perhaps a quiz. It is a<textarea>, after all, so it’s capable of being used in any form — you can even add a placeholder if you need to!


The post Creating an Editable Textarea That Supports Syntax-Highlighted Code appeared first on CSS-Tricks.

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

CSS-Tricks

, , , , ,
[Top]

To the brain, reading computer code is not the same as reading language

One of the things I do when teaching beginning front-end development is ask students to describe what it’s like to read HTML. I give them pretty basic markup for a long-form article, and ask them to read it twice: first in the code, then on the front end.

The #1 common response I hear? It’s like learning a new language.

Of course it is, I tell them. It’s in the name: Hypertext Markup Language. So, I advise them to start treating the materials in the course like they’re learning French, Spanish, or any other language.

Then I wake up this morning and see this MIT study that reading computer code is not the same as reading language, even though they share similarities.

In spite of those similarities, MIT neuroscientists have found that reading computer code does not activate the regions of the brain that are involved in language processing. Instead, it activates a distributed network called the multiple demand network, which is also recruited for complex cognitive tasks such as solving math problems or crossword puzzles.

Duh, you might say. But wait, reading code actually appears to activate additional parts of the multiple demand network that make the task more or a near-match to mathematical reasoning than the exact same thing.

The MIT team found that reading computer code appears to activate both the left and right sides of the multiple demand network […]. This finding goes against the hypothesis that math and coding rely on the same brain mechanisms.

So, back to my HTML reading assignment. Is it better to teach code as a language for recognizing symbols that communicate to the browser what to do, or as a math skill that’s based on solving problems?

The answer is 🤷‍♂️.

The most interesting thing about the study to me is not how to teach code, but rather how how I work with it. Chris always says a front-end developer is aware, and the fact that reading code taps on a region of the brain that’s responsible for handling multi-tasking and holding lots of information only supports that. It also explains why I personally get annoyed when I’m pulled away from my code or distracted from it—it’s like my brain has to drop all the plates it was balancing to pay attention to something else, then pick up and reassemble all the pieces before I can jump back in to what I was doing.

Direct Link to ArticlePermalink


The post To the brain, reading computer code is not the same as reading language appeared first on CSS-Tricks.

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

CSS-Tricks

, , , , ,
[Top]