Web Standards

Fixed Headers and Jump Links? The Solution is scroll-margin-top

Css Tricks - Fri, 02/21/2020 - 11:48am

The problem: you click a jump link like <a href="#header-3">Jump</a> which links to something like <h3 id="header-3">Header</h3>. That's totally fine, until you have a position: fixed; header at the top of the page obscuring the header you're trying to link to!

Fixed headers have a nasty habit of hiding the element you're trying to link to.

There used to be all kinds of wild hacks to get around this problem. In fact, in the design of CSS-Tricks as I write, I was like, "Screw it, I'll just have a big generous padding-top on my in-article headers because I don't mind that look anyway."

But there is actually a really straightforward way of handling this in CSS now.

h3 { scroll-margin-top: 5rem; /* whatever is a nice number that gets you past the header */ }

We have an Almanac article on it, which includes browser support, which is essentially everywhere. It's often talked about in conjunction with scroll snapping, but I find this use case even more practical.

Here's a simple demo:

CodePen Embed Fallback

In a related vein, that weird (but cool) "text fragments" link that Chrome shipped takes you to the middle of the page instead, which I think is nice.

The post Fixed Headers and Jump Links? The Solution is scroll-margin-top appeared first on CSS-Tricks.

Inspiring high school students with HTML and CSS

Css Tricks - Fri, 02/21/2020 - 11:48am

Here’s a heartwarming post from Stephanie Stimac on her experience teaching kids the very basics of web development:

[...] the response from that class of high school students delighted me and grounded me in a way I haven't experienced before. What I view as a simple code was absolute magic to them. And for all of us who code, I think we forget it is magic. Computational magic but still magic. HTML and CSS are magic.

Publishing anything on the web is always going to be magic to some degree but sometimes it’s easy to forget on a day to day basis. We have to brush off the cobwebs! Shake our tailfeathers! And remind ourselves and everyone around us that the basics of web development are precious and fun and exciting still. Especially so we can help inspire the next generation of web designers and developers.

Direct Link to ArticlePermalink

The post Inspiring high school students with HTML and CSS appeared first on CSS-Tricks.

iOS 13 Design Guidelines, Templates, and Downloads

Css Tricks - Fri, 02/21/2020 - 4:46am

Erik Kennedy wrote up a bunch of design advice for designing for the iPhone. Like Apple's Human Interface Guidelines, only illustrated and readable, says Erik.

This is mostly for native iOS apps kinda stuff, but it makes me wonder how much of this is expected when doing a mobile Progressive Web App. On one hand, this kind of stuff looks fun to try to build on the web, and it would be kinda cool to make your web app feel super native. On the other hand, doesn't that make it extra awkward for Android and other non-iOS platforms?

A few other thoughts:

  • How much of this stuff do you get "for free" with SwiftUI?
  • As I understand it, when you build apps with Flutter / Material, the native apps that get built do some smart cross-platform stuff, mimicking how that platform does things.

Erik also does very in-depth design training with enrollment only opening once in a while, the next opens March 4th.

Direct Link to ArticlePermalink

The post iOS 13 Design Guidelines, Templates, and Downloads appeared first on CSS-Tricks.

Animate SVG Path Changes in CSS

Css Tricks - Thu, 02/20/2020 - 11:49am

Every once in a while I'm motivated to attempt to draw some shapes with <path>, the all-powerful drawing syntax of SVG. I only understand a fragment of what it all can do, but I know enough to be dangerous. All the straight-line syntax commands (like L) are pretty straightforward and I find the curved Q command fairly intuitive. Box yourself into a viewBox="0 0 100 100" and drawing simple stuff doesn't seem so bad.

Here's a classic example of mine that draws things with all the basic commands, but also animates them with CSS (Chromium browsers only):

CodePen Embed Fallback

Weird but true:

<svg viewBox="0 0 10 10"> <path d="M2,2 L8,8" /> </svg> svg:hover path { transition: 0.2s; d: path("M8,2 L2,8"); }

The other day I had a situation where I needed a UI element that has a different icon depending on what state it's in. It was kind of a "log" shape so the default was straight lines, kinda like a hamburger menu (only four lines so it read more like lines of text), then other various states.

  1. DEFAULT
  2. ACTIVE
  3. SUCCESS
  4. ERROR

First I wrote the most complicated state machine in the world:

const indicator = document.querySelector(".element"); let currentState = indicator.dataset.state; indicator.addEventListener("click", () => { let nextState = ""; if (currentState == "DEFAULT") { nextState = "ACTIVE"; } else if (currentState == "ACTIVE") { nextState = "SUCCESS"; } else if (currentState == "SUCCESS") { nextState = "ERROR"; } else { nextState = "DEFAULT"; } indicator.dataset.state = nextState; currentState = nextState; });

That opened the door for styling states with data-attributes:

.element { &[data-state="DEFAULT"] { } &[data-state="ACTIVE"] { } &[data-state="SUCCESS"] { } &[data-state="ERROR"] { } }

So now if my element starts with the default state of four lines:

<div class="element" data-state="DEFAULT"> <svg viewBox="0 0 100 100" class="icon"> <path d="M0, 20 Q50, 20 100, 20"></path> <path d="M0, 40 Q50, 40 100, 40"></path> <path d="M0, 60 Q50, 60 100, 60"></path> <path d="M0, 80 Q50, 80 100, 80"></path> </svg> </div>

...I can alter those paths in CSS for the rest of the states. For example, I can take those four straight lines and alter them in CSS.

Note the four "straight" lines conveniently have an unused curve point in them. Only paths that have the same number and type of points in them can be animated in CSS. Putting the curve point in there opens doors.

These four new paths actually draw something close to a circle!

.editor-indicator { &[data-state="ACTIVE"] { .icon { :nth-child(1) { d: path("M50, 0 Q95, 5 100,50"); } :nth-child(2) { d: path("M100, 50 Q95, 95 50,100"); } :nth-child(3) { d: path("M50,100 Q5, 95 0, 50"); } :nth-child(4) { d: path("M0, 50 Q5, 5 50, 0"); } } } }

For the other states, I drew a crude checkmark (for SUCCESS) and a crude exclamation point (for FAILURE).

Here's a demo (again, Chromium), where you can click it to change the states:

CodePen Embed Fallback

I didn't end up using the thing because neither Firefox nor Safari support the d: path(); thing in CSS. Not that it doesn't animate them, it just doesn't work period, so it was out for me. I just ended up swapping out the icons in the different states.

If you need cross-browser shape morphing, we have a whole article about that.

The post Animate SVG Path Changes in CSS appeared first on CSS-Tricks.

A Guide to Console Commands

Css Tricks - Thu, 02/20/2020 - 4:48am

The developer’s debugging console has been available in one form or another in web browsers for many years. Starting out as a means for errors to be reported to the developer, its capabilities have increased in many ways; such as automatically logging information like network requests, network responses, security errors or warnings.

There is also a way for a website’s JavaScript to trigger various commands that output to the console for debugging purposes. These commands are contained in a console object available in almost every browser. Even though these features are mostly consistent between browsers, there are a few differences. Some of these differences are simply visual in nature while others do have slight functional differences to keep in mind.

For the curious, here’s the spec by WHATWG linked from the MDN console docs.

This guide covers what’s available in the console object of Firefox and Chrome as they are often the most popular browsers for development and they do have a few differences in various aspects of the console. The new Chromium-based Edge is essentially the same as Chrome in many ways so, in most cases, the console commands will operate much the same.

Quick Links The console.log command

The first thing we can do is log the console object itself to see what your browser of choice actually offers.

console.log(console);

This command will output the various properties of the console object as the browser knows them. Most of them are functions and will be rather consistent regardless of browser. If there are differences in the properties of the console object from one browser to another, this way you can see the differences. One such difference I can point out between Firefox and Chrome is that Chrome provides a “memory” property that outputs some basic memory usage stats. Firefox doesn’t provide this property and yet has a “name” property that Chrome does not have.

Thankfully, most of the differences between the browsers tend to be just as trivial. That way, you can be fairly confident that your code will output much the same regardless of the browser in use.

First things first: clear()

With heavy usage of the console comes a very crowded output of text. Sometimes you just want to clear things out and start with a fresh console. Browsers typically provide a button in DevTools that performs this task. However, the console object itself also provides a command to handle this:

console.clear();

This will clear the console and will helpfully inform you of that by outputting a message like "Console was cleared."

Common usage: debug(), error(), info(), log(), and warn()

There are five commands that at first glance seem to do the exact same thing. And, technically, they do. But browsers provide additional features tied to the five commands to give each their own distinct benefit.

These five commands are:

console.debug(); console.error(); console.info(); console.log(); console.warn();

I’m sure many of you have seen console.log() before (I mean, we just talked about it up top) and have probably used it before. Before we get into what you can log in these five commands, let’s see our first minor difference between Chrome and Firefox.

Chrome console showing debug, error, info, log, and warn

This is an example in Chrome of each command outputting a string, such as console.debug('console.debug()');.  Notice that some of them have a color treatment to give a visual indication of the type of output it is. The error and warn outputs have an additional icon for even easier identification.

Firefox console showing debug, error, info, log, and warn

Here is the same list in Firefox and, while it looks similar, there are three minor differences. For example, console.debug() is not color-coded and console.info() has an additional icon next to it. In Chrome, both console.error() and console.warn() can be expanded to show additional information about the output while Firefox only does this with console.error(). This additional information provides a trace of the lines of code involved to get to where the particular command was called.

One thing that is useful about these five commands is that the browsers provide filtering options to show or hide each type as you wish. Firefox has them right there at the top of the console above the output while Chrome hides them in a dropdown, labeled “All levels” which you can see in the earlier Chrome console screenshot. “All levels” is there because I have all five set to be shown. If you were to choose the “Default” option then the debug output (listed as "Verbose") is hidden while the others are shown. Unchecking "Info", "Warnings", or "Errors" causes the dropdown to display a different title such as "Custom levels" or "Errors only" depending on what is selected.

The intentions for usage of error and warn are easy to determine; how to use the other choices is up to you. If you do make extensive use of the different options then you might consider documenting the expectations of each as to not confuse things late in the project — especially if it is a team project.

Now, let’s discuss what we can actually log inside these commands. Since they all behave the same, I’ll just focus on logging as the example.

The simplest examples involve just passing a string, number, object, or array into the log command. Technically, any of JavaScript’s data types can be used, but for most of them, the output is much the same.

console.log('string'); console.log(42); console.log({object: 'object'}); console.log(['array', 'array']); Chrome string, number, object, and array log examples

I’m showing these examples in Chrome with the object and array already expanded. They are normally collapsed but the output next to the arrow is consistent between both states. Firefox displays a little differently but, for the most part, the output is the same. Firefox does tell you whether it is displaying an object or array before expanding, but shows the same as Chrome while expanded.

One interesting thing to add is that you can pass more than one item to the log as parameters and it’ll display them inline.

console.log('string', 'string'); console.log(42, 1138); console.log({object: 'object'}, {object: 'object'}); console.log(['array', 'array'], ['array', 'array']); Chrome strings, numbers, objects, and arrays examples

Often when I’m working with x and y coordinates, such as what can be outputted by mouse events, it’s useful to log the two together in one statement.

String substitution

The different console logging commands provide string substitution that allows inserting different values into the string for output. This is useful for describing a variable in the log to make it clear as to what’s being reported.

console.log('This is a string: %s', 'string'); console.log('This is a number: %i', 42); console.log('This is an object: %o', {object: 'object'}); Chrome string substitution examples

Here is a list of the data types that can substituted into the output string:

Data typeSubstitution symbol Objects and arrays %o or %O Integers %d or %i Strings %s Floats %f

The first parameter would be the string to output with the symbols placed in the appropriate locations. Then each parameter after that is the value to substitute inside the first parameter’s string. Keep in mind that you’ll have to keep the substitution types and the parameters in the specific order or you’ll get unexpected results.

If your console supports template literals, it’s a bit easier to get similar results as string substitutions.

console.log(`This is a string: ${'string'}`); console.log(`This is a number: ${42}`); console.log(`This is an object: ${{object: 'object'}}`); Chrome template literal examples

Notice that the object is handled a bit better with the string substitution, so pick the appropriate choice for your requirements. Since it’s possible to insert more than one value in the output, let’s compare the two.

console.log('This is a string: %s. This is a number: %i', 'string', 42); console.log(`This is a string: ${'string'}. This is a number: ${42}`); Chrome string substitution and template literals

With the string substitution each value is added as a parameter to be inserted into the output. With template literals, on the other hand, you add them wherever they need to be in the output. Also, you can combine them.

console.log(`This is a number: ${42}. This is an object: %o`, {object: 'object'}); Chrome string substitution with template literals

So, there are lots of options to pick and choose from so you can go with the best options for your needs. 

Styling the output

Another potentially useful and fun thing is that you can apply CSS styles to the console’s output. It works just like the string substitution method where you insert a %c variable for styles to be applied from the parameters.

Here’s a simple example:

console.log('%cThis is large red text', 'color: red; font-size: 30px;'); Chrome styling in the console

This time there is a slight difference in the Firefox output:

Firefox styling in the console

Not really that much of a difference, but something to keep in mind.

What essentially happens is that %c reads the strings in the parameters to determine what styling to apply. So, say there’s a second styling being passed, %c moves on to the next parameter, much like with string substitution. An empty string in the parameter list resets the styling back to default.

console.log('This is %cred text %cand this is %cgreen text.', 'color: red;', '', 'color: green;'); Using multiple styles in the Chrome console.

The styling properties available are rather limited when compared to typical CSS styling on a webpage. You can look at it as a sort of inline block of text that allow you to manipulate a limited set of styling properties.

With some work and experimenting, you could create interesting messaging within the console. One idea is to draw extra attention to a particular log, especially an error of some sort.

console.log('%cHello there!', `   background: white;   border: 3px solid red;   color: red;   font-size: 50px;   margin: 40px;   padding: 20px; `); Chrome custom styling

In this example, we can see that the CSS is a bit verbose, but there is something we can do to mimic the class system that we leverage in CSS. The values of each parameter for styling can be stored in variables to allow for repeated use without having to duplicate the string of styles in each parameter.

const clearStyles = ''; const largeText = 'font-size: 20px;'; const yellowText = 'color: yellow;'; const largeRedText = 'font-size: 20px; color: red;'; const largeGreenText = 'font-size: 20px; color: green;'; ? console.log(`This is %clarge red text. %cThis is %clarge green text. %cThis is %clarge yellow text.`,   largeRedText,   clearStyles,   largeGreenText,   clearStyles,   largeText + yellowText ); Chrome custom template styling

There are several things going on here, so let’s break it down a bit. First, we have a collection of variables that holds our styling strings. Think of each as a sort of class to be reused in the parameters of the console log.

We are also using a template literal in the log, which means we can have line breaks in our output. Then, for each %c in the text, there’s a corresponding variable used in a parameter to define the styles for that particular part of the output text. In addition to each variable that holds styling, there is also a clearStyles argument that can be used to reset styles to prepare for the next set of styling. You could just use an empty string as in previous examples, but I like the clear intention that comes from using the variable name. The last parameter shows that the variables can be combined, which opens up more possible ways of handling the styles.

Now, that’s a great deal of text covering essentially five console commands that only output text to the console. So, let’s move on to other commands of the console object. Although, some of these can still use many of the features described so far, we won’t focus on that aspect as much with the following commands.

Being assertive: assert()

The console.assert() command is similar to the error command mentioned previously. The difference is that asserting allows for the usage of a boolean condition to determine whether it should output the text to the console.

For example, let’s say you wanted to test the value of a variable and make sure it wasn’t larger than a certain number value. If the variable is below that number and the condition resolves to true, the assert command does nothing. If the condition resolves to false, then the output text is displayed. This way you don’t have to wrap a console.error() command with an if statement to determine if the error message is needed in the first place.

let value = 10; console.assert(value <= 7, 'The value is greater than 7.'); Chrome assert example

We can see that assert has the same appearance as the error command, except that it also prepends “Assertion failed:” to the output text. Chrome can also expand this output to show a trace of where the assertion came from.

The trace can be quite helpful with common patterns of functions within functions calling other functions and so on. Although, you can see in the example above that the line the assert came from doesn’t tell you how the code got to that line.

let value = 10; ? function function_one () {   function_two(); } ? function function_two () {   function_three(); } ? function function_three() {   console.assert(value < 7, 'This was false.'); } ? function_one(); Chrome assert with trace

This sequence is actually in reverse order in terms of the code. The last line shows an anonymous entry (which is an HTML script tag in this case) on line 78. That’s where function_one was called. Inside that function, we have a call for function_two, which, in turn, calls function_three. Inside that last function is where the assert is located. So, in this development world of functions sharing other functions; a description of the path to that point of the assert is quite handy.

Unfortunately, this trace is not provided in Firefox with the assert command, as it is with the error command.

Firefox assert example Keeping count: count() and countReset()

Ever wonder how many times a certain thing happens in your code? For instance, how many times does a particular function get called during a sequence of events? That’s where the console.count() command can help out.

By itself, the count command is rather simple and has limited use. If you use the command in its default state you only get a simple count. For example, if we call it three times in a row, we get a sequential count.

console.count(); console.count(); console.count(); Chrome default count example

As you can see, we get a simple count from one to three. The default behavior means that count is merely incrementing the output by one each time it runs, no matter where it shows up in the code. You do get the line number in the code where it happened, but the count is a simple total no matter the situation.

To make this command a bit more useful, we can provide a label to keep a separate count for that label.

console.count('label A'); console.count('label B'); console.count('label A'); console.count('label B'); console.count('label A'); console.count('label B'); Chrome label count example

Even though using the count command with labels causes the output to alternate between labels, each one keeps its own count. One scenario where this comes in handy is placing a count inside a function so that every time that function is called, the count is incremented. The label option makes it so that a count can be kept for individual functions to provide for a good idea of how many times each function is being called. That’s great for troubleshooting performance bottlenecks or simply seeing how much work a page is doing.

There’s a way to reset the count. Let’s say we have a loop that gets called multiple times, but the number of iterations of the loop can be dynamic. This is done with the console.countReset() command with the same label from the count command.

console.count(); console.count(); console.countReset(); console.count(); ? console.count('this is a label'); console.count('this is a label'); console.countReset('this is a label'); console.count('this is a label'); Chrome count reset example

Each count — with and without a label — is called twice and console.countReset() is applied right before another count instance. You can see that Chrome counts up to two, then restarts when it encounters countReset. There’s nothing in DevTools to indicate the reset happened, so an assumption is made that it did happen because the count started over.

And yet, the same code is a bit different in Firefox.

Firefox count reset example

Here, the reset is indicated by the count being set all the way back to zero. That is the indicator that the reset was called, whereas we have no such indication in Chrome.

As for label options, just about anything can be used. I suppose a simple way to describe it is that if you give it anything that can be resolved to a string, it’ll probably work as a label. You could even use a variable that has values that change over time, where count will use the current value of the variable as a label each time it is encountered. So, you could keep count of the values as they change over time.

Describe that thing: dir() and dirxml()

The main idea behind these two commands is to display either properties of a Javascript object with console.dir() or descendant elements of an XML/HTML element with console.dirxml(). It appears Chrome has these implemented as expected, while Firefox just uses both as aliases for console.log().

Let’s give console.log(), console.dir(), and console.dirxml() the same simple object to see what we get. Keep in mind that you normally would not log an object with console.dirxml().

const count = {   one: 'one',   two: 'two',   three: 'three' }; ? console.log(count); console.dir(count); console.dirxml(count); Chrome simple dir() and dirxml() example

Firefox gives us much the same, except the console.dir() is automatically expanded.

Firefox simple dir() and dirxml() example

Another simple comparison to console.log() is to repeat the object in the same command.

Chrome dir() and dirxml() double example Firefox dir() and dirxml() double example

Not really that much different other than that Chrome doesn’t show the second object in console.dir() like Firefox does. Which makes sense because Chrome is trying to display properties of an object (ignoring the second) while Firefox is just aliasing everything to a console.log(). So, for situations like this with objects there is little difference between console.log(), console.dir(), and console.dirxml() in the browsers.

A useful benefit of console.dir() in Chrome that I can point out is how DOM elements are handled. For example, here’s how console.log() displays in Chrome and Firefox when given a DOM element.

Chrome console.log() DOM example. Firefox console.log() DOM example

Now, I’ve always liked how Firefox outputs a DOM element inside a console.log(), as it gives you all the properties of that DOM element. So, when I wanted to look up a specific property of a DOM element to manipulate with JavaScript, it’s only a console.log() away to find it. Chrome, on the other hand, gives us the HTML code of the DOM element in the console.log() just like it would in console.dirxml().

To get the properties in Chrome, use console.dir() with the DOM element. I was quite happy to find that console.dir() in Chrome provides the properties of a DOM element just as I came to rely on that information in Firefox.

As for console.dirxml() in Chrome, it can be useful for displaying an HTML element and its children outside of the clutter of the DOM Inspector. You can even edit some of the existing HTML live in the console, but you won't have the same level of abilities as in the DOM Inspector.

Let’s get together: group(), groupCollapsed(), and groupEnd()

Here’s a simple one: Group different console outputs together to show a form of relationship among them. It is somewhat limited in features so its usefulness will depend a great deal on how you plan to use it. This is the console.group() command.

console.group(); console.log('one'); console.log('two'); console.log('three'); console.groupEnd(); ? console.group('this is a label'); console.log('one'); console.log('two'); console.log('three'); console.groupEnd(); Chrome group() example

In the first block of code we call console.group() in its default state, have three logs, and then finally call console.groupEnd(). The console.groupEnd() simply defines the end of the grouping. The second block has a string as a parameter that essentially becomes the label for that group. Notice that in the first block without a label it just identifies itself as a console.group in Chrome while in Firefox it shows as <no group label>. In most cases, you’ll want a proper label to distinguish between groups.

Also notice the arrow next to the labels. Clicking on that collapses the group. In the code examples above, if we change console.group() to console.groupCollapsed(), they start collapsed and must be opened to see the output.

You can also nest the groups. The console.groupEnd() command simply refers to the last opened group.

console.group('outer group'); console.log('outer one'); console.log('outer two'); console.group('inner group'); console.log('inner one'); console.log('inner two'); console.log('inner three'); console.groupEnd(); console.log('outer three'); console.groupEnd(); Chrome nested group() example

Just as a quick note, if you want the group label to stand out a bit more in a list of output in the console, you can style it just as we did with strings earlier.

console.group('%cstyled group', 'font-size: 20px; color: red;'); console.log('one'); console.log('two'); console.log('three'); console.groupEnd(); Chrome styled group() example Have a seat at the: table()

In previous examples, we’ve seen what happens when we put an array or object inside a console.log() or console.dir(). There’s another option for these data types for a more structured display, which is console.table().

Here’s a simple example with an array:

let basicArray = [   'one',   'two',   'three' ]; console.table(basicArray); Chrome basic array table() example

Here’s the same example in Firefox for comparison.

Firefox basic array table() example

A slight visual difference, but pretty much the same. That said, Chrome does still give you the expandable output under the table, much like you’d see in console.log(). Chrome will also provide basic column sorting if you click on the heading.

The output is similar when passing in an object:

let basicObject = {   one: 'one',   two: 'two',   three: 'three' }; console.table(basicObject); Chrome basic object table() example

So, that was a pretty simple example with basic outputs. How about something a little more complex and is often used in coding projects? Let’s look at an array of objects.

let arrayOfObjects = [   {     one: 'one',     two: 'two',     three: 'three'   },   {     one: 'one',     two: 'two',     three: 'three'   },   {     one: 'one',     two: 'two',     three: 'three'   } ]; console.table(arrayOfObjects); Chrome array of objects table() example

As you can see, this gets us a nice layout of objects with repeating keys as column labels. Imagine data along the lines of user information, dates, or whatever might be data often used in loops. Keep in mind that all the keys in each of the objects will be represented as a column, whether there is corresponding keys with data in the other objects. If an object doesn’t have data for a key’s column, it appears as empty.

An array of arrays is similar to the array of objects. Instead of keys being labels for the columns, it uses the index of the inner arrays as column labels. So if an array has more items than the other arrays, then there will be blank items in the table for those columns. Just like with the array of objects.

So far, simple arrays and objects have simple output displayed. Even a slightly more complex array of objects still has a solid, useful structure. Things can get a bit different with mixing the data types though.

For example, an array of arrays where one of the inner array items is an object.

let arrayOfArraysWithObject = [   ['one', 'two', {three: 'three', four: 'four'}],   ['one', 'two', {three: 'three', four: 'four'}],   ['one', 'two', {three: 'three', four: 'four'}] ]; console.table(arrayOfArraysWithObject); Chrome array of arrays with object table() example

Now, to see what is contained in those objects in the third column, we’ll have to expand that array output below the table. Not that bad, really. Here’s how Firefox handles the same output.

Firefox array of array with object table() example

Firefox just lets us expand the object within the table.

How about mixing the data types the other way, where we have an object with arrays as values for each key? It works much the same as the array of arrays. The difference is that each row is labeled with a key instead of the index. Of course, for each level of data type you add to the mix will result in a more complex looking table. 

This is all about: time(), timeLog(), and timeEnd()

Here we have a simple way to log how long something takes to complete. We call console.time() with a label, call console.timeLog() with the same label for an update, and call console.timeEnd() again with the same label to stop the timer.

console.time('this is a timer'); console.timeLog('this is a timer'); console.timeEnd('this is a timer');

The output for Chrome and Firefox is much the same. Here’s an example output with code that logs the time every second for five seconds and then stops.

Chrome time() example Firefox time() example

Notice that the reported times are not quite the same, but probably close enough for most requirements. Also, Firefox is nice enough to note that the timer has ended while Chrome requires an assumption once the label stops appearing. The first four lines of output come from the call console.timeLog('this is a timer'); and the last line is from the call to console.timeEnd('this is a timer');.

Dropping breadcrumbs with: trace()

The console.trace() command is actually similar to console.error() and console.warn(). Calling this command will output a stack trace to the console showing the path through the code to that call. We can even pass it a string as a form of label, but other data types such as arrays or objects can be passed. The behavior of passing data like that is the same as what we would get from a console.log() call. It’s a simple way to pass along some information to the console without triggering a more dire looking console.error() or console.warn() call.

debugger

This is a simple command to trigger a pause in the console’s debugger, if it exists. It is similar to placing a breakpoint in the debugger, or the browser’s equivalent, to cause the same type of pause while executing code. Here’s a simple example:

function whatsInHere() {   debugger;   // rest of the code }

In this particular example, the open console’s debugger will pause code execution and the browser will open up the source file to show the line of code as soon as the function is called. It could be useful for easy breakpoints with some complicated projects.

Technically, the debugger command isn't a part of the console object in the browser. It's a useful feature that the console will respond to from JavaScript code.

Some additional console utilities

That’s a good look at most of the standard commands available to us in the console object. Each of these will work more-or-less the same across modern browsers. There may be some differences between browsers, as we saw in some of the examples. But there are a few more things I’d like to take a moment to point out, as they might prove useful in various ways.

The following examples can be considered more like console “utilities.” They are not a part of the console object like most of the previous examples. Therefore they are not called with a leading console object reference. These utilities are supported directly by the browsers themselves. They cannot be called from JavaScript code but must be typed directly in the console to be used. In some cases the utility might be unique to a particular browser, in others the utility is supported much the same way in several browsers. Your mileage may vary based on your browser of choice.

$0, $1, $2, $3, $4

These five commands are extremely handy. The first one, $0, represents the currently selected element in the DOM inspector. This essentially provides a shortcut instead of having to use more traditional DOM methods, such as getElementById or a querySelector. You can use it in various ways, within various console commands, or by itself to get information about the currently selected element. For example:

console.log($0);

The other commands in this set represent elements that were previously selected. Think of them as a form of selection history. $1 is the previous element, $2 is the previous before that, and so on. Although the first command is available in Firefox, the commands for previously selected elements are not.

$(‘element’), $$(‘elements’)

If you find yourself typing out document.querySelector('element') in the console repeatedly, there’s a shortcut. You can just type $('element') and it performs the same function. The shortcut might remind many of jQuery, but to select multiple elements reminds me of MooTools. To select multiple elements, you’d use $$('elements') instead of document.querySelectorAll('elements').

$x(‘//element’)

This is a shortcut for XPath that will return an array of elements that match the expression. An easy example is $x('//div'), which will present an array of every div element on the page. This isn’t that much different than using $$('div') like we did with $('element'), but there are many options for writing XPath expressions.

One example of a simple step up in a XPath expression is $x('//div[descendant::span]') (thanks to Neil Erdwien for the correction), which would return the div elements on the page that happen to contain a span element. This is the equivalent of :has in CSS Selectors Level 4 draft, which isn’t supported in browsers yet.

These are just basic examples that only scratch the surface of XPath.

clear()

This is another version of console.clear(), but without the “Console was cleared” message.

getEventListeners(object)

This command, when given a DOM element, will report the event listeners registered to that element. For example, using the $0 example from above we can use getEventListeners($0) to get something like this:

Chrome getEventListeners() example

Expanding each item in the array provides various information about that event listener. This function isn’t supported in Firefox, but it does offer something similar that can be found in the DOM inspector.

Firefox DOM Inspector events information.

Clicking on the “event” badge next to the element provides a list of events registered to the element. Then each event can be expanded to show the code involved with the event.

That’s it for now!

 I’ll end it here, with a large amount of information detailing various commands that can be used in the browser’s console output or with JavaScript. This isn’t everything that is possible — there’s simply too much to cover. In some cases, each browser has its own capabilities or utilities that can be leveraged. We looked at the bulk of what we might find in Chrome and Firefox, but there’s likely more out there. Plus, there will always be new features introduced in the future. I invite you to dig deeper to discover more ways to leverage browser DevTools for your coding projects.

The post A Guide to Console Commands appeared first on CSS-Tricks.

Add Background Colors to SVGs Using the “rect” Element

Css Tricks - Thu, 02/20/2020 - 4:43am

The advantages of using SVGs in web development are well known. SVGs are small in size, can be made quite accessible, are scalable while maintaining their quality, and can be animated. Still, there is a learning curve. Things, like the syntax of SVG, can be a little tricky and having to hand-alter SVG code sometimes isn’t out of the question.

Most SVG assets allow styling to be applied in predictable ways. For instance, this circle has a hover state that functions much like any other element in the DOM.

CodePen Embed Fallback

However, a problem I've encountered on several front-end projects is being provided a sub-optimal SVG asset by a client, designer, or brand resources site. There isn’t anything “wrong” with these files, but the SVG code requires manual revision to achieve necessary functionality. Instead of requesting new files, it is often easier to tweak them myself. 

Styling SVGs is complicated by the fact that, as XML-based files, they act like HTML in some respects, but not in others. Let’s work with an example provided by Instagram themselves (which is also easily findable on Wikipedia). Because the spaces in between paths act as a sort of transparency this image displays whatever background has been applied behind it.

Why isn’t there a background color on the SVG so we can apply a color change on hover (e.g. svg:hover { background: #888; })? It’s because the paths fill the reverse of the space you would think they would. The negative space renders whatever sits behind this element (<body> in the CodePen examples below). Often this is not a problem and may even be desirable for large background designs to ensure organic transitions between content areas. However, because I am using this SVG as a link, I will need to alter the file so that I can style the space behind it. 

<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> <title>Instagram</title> <path d="..." transform="translate(0 0)" fill="#fff"/> <path d="..." transform="translate(0 0)" fill="#fff"/> <path d="..." transform="translate(0 0)" fill="#fff"/> </svg>

The Instagram logo is a perfect example of an awkward SVG file that requires more CSS finesse than most. Again, there is nothing wrong with this SVG, but it presents some challenges for styling. In order to add a hover state that alters the background, we will need to change the code above.

There are several ways to go about this, but the easiest fix is to add another element behind the image. Because the Instagram icon is rectangular, we can add a <rect> element behind the three foreground paths that comprise this SVG. If the logo was circular or oval, I would have used the <circle> or <ellipse> element. Be sure to set a height and width to match the viewBox when adding this type of element, and use the rx value to round the corners as needed. Rather than adding a class or fill to every path in the SVG element, we can target the <rect> and <path> elements in the CSS file. 

CodePen Embed Fallback

The advantage of this approach is its simplicity. Instead of having to alter multiple files or use JavaScript or third-party JavaScript libraries, we can add one line of code to the SVG code block and style it. 

If, for some reason, you need or just prefer to leave the SVG file alone, you can revise the CSS to achieve similar functionality. 

We could add a background property on the social-link class but, for this tutorial, I will instead use the slightly more complicated, but equally effective, strategy of revising an SVG by applying a pseudo-element to it. In the example below, I have used the ::before pseudo-class to add a shape and the opacity property to make it visible on hover. To avoid having this shape leave a border around the icon, I have made it slightly smaller than the SVG using the height and width properties (calc(100% - 2px)). Then I center the pseudo-element behind the SVG and match the transition property for both element and pseudo-element.

/* Sets the link's dimensions */ .social-link { display: block; height: 24px; position: relative; width: 24px; } /* Targets the pseudo-element to create a new layer */ .social-link::before { background: #fff; border-radius: 2px; content: ""; display: block; height: calc(100% - 2px); opacity: 0; position: absolute; transition: all 0.2s ease-in-out; width: calc(100% - 2px); } /* Changes the background color of the pseudo-element on hover and focus */ .social-link::before:hover, .social-link::before:focus { background: #000; } /* Makes sure the actual SVG element is layered on top of the pseudo-element */ .social-link svg { position: relative; z-index: 1; } /* Makes the background-color transition smooth */ .social-link svg path { transition: all 0.2s ease-in-out; } /* SVG paths are initially white */ .social-link path { fill: #fff; } /* The pseudo-elememt comes into full view on hover and focus */ .social-link:hover::before, .social-link:focus::before { opacity: 1; } /* Fills the SVG paths to black on hover and focus */ .social-link:hover svg path, .social-link:focus svg path { fill: #000; } CodePen Embed Fallback

I recommend the above strategies for a quick fix because using vanilla JavaScript or a JavaScript library like vivus.js or raphaeljs is overkill for adding a hover state to an SVG in most cases. However, there are times when modifying an SVG using JavaScript is preferable. Because JavaScript is undoubtedly the most flexible method to change styles, let’s examine what this might look like.

My example separates the JavaScript file, but if you want to add JavaScript inside the SVG element itself, you will need to add a <script> element, just like an HTML file. Be sure to add a CDATA marker to your <script> element to ensure it is parsed as XML.

CodePen Embed Fallback

I’m using jQuery to simplify things a bit and keep CSS as minimal as possible, although for clarity sake, I have added a background property on the social-link class in the CSS file rather than adding it via JavaScript. Notice that this solution targets svg path when altering the CSS method rather than assigning a class to these paths because, in this case, each path should be treated the same.

There are many many ways to style SVGs, but the examples collected in this article are useful and extensible. Strategies for altering SVG files need to be evaluated by an app’s full functionality, but I suspect most front-end developers will find that the <rect> element offers the simplest and most readable solution.

Acknowledgements

Many thanks to Joe Essey and my front-end pals at Nebo Agency Allison Lewis and Nile Livingston (check out Nile’s article, “SVGs for the Web”). 

The post Add Background Colors to SVGs Using the “rect” Element appeared first on CSS-Tricks.

Seen by Indeed

Css Tricks - Thu, 02/20/2020 - 4:43am

(This is a sponsored post.)

Are you looking for a tech job where you clock in, or for a career where you’ll be seen?

Seen by Indeed is a matching service for software engineers, product managers and other tech pros that sorts through thousands of companies -- like Twilio, Overstock, VRBO, and PayPal -- and matches tech talent like you to the role that’ll take you further. Not only does Seen by Indeed match on things like skills, experience and salary, but we’re with you every step of the way with free one-on-one career coaching, resume reviews and in-depth resources.

So, whether you need negotiation tips, networking strategies or just want to talk to someone about your career, Seen by Indeed has you covered. In fact, you can start by getting a free resume review that covers formatting, how to beat the resume-screening bots and personalized tips on how to show yourself off.

What are you waiting for? Put Indeed’s new tech-focused matching platform to use to move up in your career.

Direct Link to ArticlePermalink

The post Seen by Indeed appeared first on CSS-Tricks.

Footnote Characters

Css Tricks - Wed, 02/19/2020 - 2:47pm

There are special superset number characters that are sometimes perfect for footnotes. Here they are:

¹ ² ³ ? ? ? ? ? ?

I generally prefer to superscript the number myself, like:

<p>This next word<sup>1</sup> has a footnote.</p>

That way I can select it in CSS or JavaScript in case I want to do something special with it.

You'd probably add an anchor link around that as well to link to an ID elsewhere on the page that explains the footnote.

But sometimes it just isn't practical or possible to use HTML as you author a bit of text. As I type, I'm writing in the WordPress Gutenberg editor. I can write in HTML block if I want, but it's much more practical to use the default paragraph blocks, which have options for stuff like bold, italic, and strikethrough, but not for superscript. I don't really wanna convert a block to HTML just to use a superscript number. So, a special Unicode character¹ it is.

  1. Another thing the Gutenberg editor can't do is add an ID to a link, so it's not really practical for me to offer a "jump back to the footnote" link down here. Sad face.

The post Footnote Characters appeared first on CSS-Tricks.

Do This to Improve Image Loading on Your Website

Css Tricks - Wed, 02/19/2020 - 2:47pm

In the video embedded below, Jen Simmons explains how to improve image loading by using width and height attributes. The issue is that there’s a lot of jank when an image is first loaded because an img will naturally have a height of 0 before the image asset has been successfully downloaded by the browser. Then it needs to repaint the page after that which pushes all the content around. I’ve definitely seen this problem a lot on big news websites.

Anyway, Jen is recommending that we should add height and width attributes to images like so:

<img src="dog.png" height="400" width="1000" alt="A cool dog" />

This is because Firefox & Chrome will now take those values into consideration and remove all the jank before the image has loaded, even when you override those values in CSS with a fluid width and thus unknown height. That means content will always stay in the same position, even if the image hasn’t loaded yet. In the past, I’ve worked on a bunch of projects where I’ve placed images lower down the page simply because I want to prevent this sort of jank. I reckon this fixes that problem quite nicely.

Direct Link to ArticlePermalink

The post Do This to Improve Image Loading on Your Website appeared first on CSS-Tricks.

monica.css

Css Tricks - Wed, 02/19/2020 - 1:47pm

Monica Dinculescu:

I don’t want every possible padding and margin and colour and flexbox configuration in the world. I just want the ones that I know I end up using in every project. So here is monica.css: my very own CSS framework, which I copy paste at the beginning of every CSS file and take it from there.

I love it when people make their own CSS starter. I like Sanitize, but even that feels like a bit much for most things I poke around at. If I was making one for myself, I'd probably steal some of this stuff from Monica. I'd definitely pull the margin off body as I find myself writing that line a lot. I'd probably steal some of that [class] stuff from Andy's. My center class would probably just be text-align and I'd give myself some other centering class for my other favorite centering: display: grid; place-items: center;.

I love how everyone agrees on box-sizing.

Direct Link to ArticlePermalink

The post monica.css appeared first on CSS-Tricks.

Understanding Web Accessibility Color Contrast Guidelines and Ratios

Css Tricks - Wed, 02/19/2020 - 5:36am

What should you do when you get a complaint about the color contrast in your web design? It might seem perfectly fine to you because you’re able to read content throughout the site, but to someone else, it might be a totally different experience. How can put yourself in that person’s shoes to improve their experience?

There are some relatively easy ways to test contrast. For example, you can check the site on your phone or tablet in bright sunlight, or add a CSS filter to mimic a grayscale view). But… you don’t have to trust your eyes. Not everyone has your exact eyes anyway, so your subjective opinion can possibly be a faulty measurement. 

You can mathematically know if two colors have enough contrast between them. 

The W3C has a document called Web Content Accessibility Guidelines (WCAG) 2.1 that covers  successful contrast guidelines. Before we get to the math, we need to know what contrast ratio scores we are aiming to meet or exceed. To get a passing grade (AA), the contrast ratio is 4.5:1 for most body text and 3:1 for larger text. 

How did the W3C arrive at these ratios?

The guidelines were created for anyone using a standard browser, with no additional assistive technology. The contrast ratios that the WCAG suggests were based initially on earlier contrast standards and adjusted to accommodate newer display technologies, like antialiased text, so content would be readable by people with a variety of visual or cognitive difficulties, whether it be due to age, sickness, or other losses of visual acuity.  

We’re basically aiming to make text readable for someone with 20/40 vision, which is equivilent to the vision of someone 80 years old. Visual acuity of 20/40 means you can only read something at 20 feet away that someone with perfect 20/20 vision could read if it was 40 feet away.

So, say your design calls for antialiased text because it looks much smoother on a screen. It actually sacrifices a bit of contrast and ding your ratio. The WCAG goes into more detail on how scoring works.

There are other standards that take contrast in consideration, and the WCAG used some of these considerations to develop their scoring. One is called the Human Factors Engineering of Computer Workstations (ANSI/HFES 100-2007) was published in 2007 and designated as an American standard for ergonomics. It combined and replaced two earlier standards that were created by separate committees. The goal of the combined standard was to accommodate 90% of computer users, and cover many aspects of computer use and ergonomics, including visual displays and contrast. So, that means we have physical screens to consider in our designs.

What does the ratio mean?

The contrast ratio explains the difference between the lightest color brightness and the darkest color brightness in a given range. It’s the relative luminance of each color.

Let’s start with an egregious example of a teal color text on a light gray background. 

<h1>Title of Your Awesome Site</h1> h1 { background-color: #1ABC9C; color: #888888; } Yikes!

It’s worth calling out that some tools, like WordPress, provide a helpful warning for this when there’s a poorly contrasted text and background combination. In the case of WordPress, a you get notice in the sidebar.

"This color combination may be hard for people to read. Try using a brighter background color and/or a darker text color."

“OK,” you say. “Perhaps you think that teal on gray color combination is not exactly great, but I can still make out what the content says.“ (I’m glad one of us can because it’s pretty much a muddy gray mess to me.)

The contrast ratio for that fine piece of hypertext is 1.47:1.

I wanted a better understanding of what the contrast scores were actually checking and came to find that it requires the use of mathematics… with a side of understanding the differences between human and computer vision.  This journey taught me about the history of computer vision and a bit about biology, and gave me a small review of some math concepts I haven’t touched since college.

Here’s the equation:

(L1 + 0.05) / (L2 + 0.05)
  • L1 is the relative luminance of the lighter of the colors.
  • L2 is the relative luminance of the darker of the colors.

This seems simple, right? But first we need to determine the relative luminance for each color to get those variables.

OK, back to relative luminance

We mentioned it in passing, but it’s worth going deeper into relative luminance, or the relative brightness of any color expressed into a spectrum between 0 (black) and 1 (white).

To determine the relative luminance for each color, we first need to get the RGB notation for a color. Sometimes we’re working with HEX color values and need to covert that over to RGB. There are online calculators that will do this for us, but there’s solid math happening in the background that makes it happen. Our teal hex color, #1ABC9C, becomes an RGB of 26, 188, 156.

Next, we take each value of the RGB color and divide each one by 255 (the max integer of RGB values) to get a linear value between 0 and 1. 

So now with our teal color it looks like this:

ComponentEquationValueRed26/2550.10196078Green188/2550.73725490Blue156/2550.61176471

Then we apply gamma correction, which defines the relationship between a pixel's numerical value and its actual luminance, to each component part of the RGB color. If the linear value of a component is less than .03938, we divide it by 12.92. Otherwise, we add .055 and divide the total by 1.055 and take the result to the power of 2.4.

Our gamma corrected color components from our teal color end up like this:

ComponentEquationValueRed((0.10196078 +.055)/1.055) ^ 2.40.01032982Green((0.73725490 +.055)/1.055) ^ 2.40.50288646Blue((0.61176471 +.055)/1.055) ^ 2.40.33245154

This part of our equation comes from the formula for determining relative luminance.

We just sort of sped past gamma correction there without talking much about it and what it does. In short, it translates what a computer "sees” into the human perception of brightness. Computers record light directly where twice the photons equals twice the brightness. Human eyes perceive more levels of light in dim conditions and fewer in bright conditions. The digital devices around us make gamma encoding and decoding calculations all the time. It’s used to show us things on the screens that match up to our perception of how things appear to our eyes.

Finally, we multiply the different colors by numbers that signify how bright that color appears to the human eye. That means we determine the luminance of each color by multiplying the red component value by .2126, the green component value by .7152, and the blue component by .0722 before adding all three of those results together. You'll note that green gets the highest value here,

So, one last time for teal:

ComponentEquationValueRed0.01032982  X 0.21260.00219611973Green0.50288646  X 0.71520.35966439619Blue0.33245154  X 0.07220.02400300118

...and add them together for luminance!

L1 = 0.00219611973 + 0.35966439619 + 0.02400300118 = 0.38586352

If we do the same to get our L2 value, that gives us 0.24620133.

We finally have the L1 and L2 values we need to calculate contrast. To determine which value is  L1 and and which is L2 , we need to make sure that the larger number (which shows the lighter color) is always L1 and is divided by the smaller/darker color as L2.

Now compare that result with the WCAG success criterias. For standard text size, between 18-22 points, a minimul result of 4.5 will pass with a grade of AA. If our text is larger, then a slightly lower score of  3 will do the job. But to get the highest WCAG grade (AAA), we have to have a contrast ratio result of at least 7. Our lovely combination fails all tests, coming far under 4.5 for regular text or 3 for headline style text. Time to choose some better colors!

I’m so glad we have computers and online tools to do this work for us! Trying to work out the details step-by-step on paper gave me a couple weeks of frustration. It was a lot of me getting things wrong when comparing results to those of automated contrast checkers.

Remember how teachers in school always wanted you to show your math work to prove how you got to the answer? I made something to help us out.

CodePen Embed Fallback

If you view this demo with the console open, you’ll see the math that goes into each step of the calculations. Go ahead, try our two example colors, like #1ABC9C and #888888.

I just want my page to have proper contrast, what do I do?!

There are a variety of accessibility resources that you can can audit your site. Here’s a list I put together, and there’s another list here on CSS-Tricks.

But here are a few tips to get you started.

First, identify areas that are not serving your accessibility needs.

The WAVE accessibility tool is a good place to start. Run your site through that and it will give you contrast results and help identify trouble areas.

Yay, passing scores! Follow the suggestions of the audit

Use best practices to improve your scores, and remove the errors. Once you identify contrast errors, you can try out some different options right there in the WAVE tool. Click on the color box to pop open a color picker. Then play around until the errors go away, and you’ll know what you can replace in your code.

Run the test again

This way, you can make sure your changes improved things. Congratulations! You just made your product better for all users, not just ones affected by the accessibility errors!

What comes next is up to you!

You can make it easier on yourself and start all new products with the goal of making them accessible. Make accessibility guidelines part of your requirements for both technology and design. You’ll save yourself potentially hundreds of hours of remediation, and potential legal complaints. U.S. government and education websites are required to comply, but other industries are often taken to task for not making their sites equally available for all people.

If you have the option, consider using established and tested frameworks and web libraries (like Bootstrap or Google’s Material Design) that have already figured out optimum contrast theme colors. In many cases, you can take just what you need (like only the CSS) or at least review their color palettes to inform choices. You should still check the contrast though because, while most standard text options in a framework may follow contrast ratio WCAG suggestions, things like alert and message styles may not. (I’m looking at you, Bootstrap!)

Derek Kay has reviewed a list of web frameworks with a focus on accessibility, which I suggest you read if you are looking for more options. The U.S. Web Design System shows one way to solve color/contrast puzzles using their CSS token system that labels colors to make contrast differences super clear), but they also link to several very good resources for improving and understanding contrast.

We took a deeper dive here than perhaps you ever really need to know, but understanding what a contrast ratio is and what it actually means should help you remember to keep contrast in mind when designing future sites, web apps, and other software.

Having a clearer understanding of what the contrast ratio means helps me to remember who poor contrast can affect, and how to improve web and mobile products overall.

I’m not the ultimate subject expert on contrast, just a very, very curious girl who sometimes has issues reading things on the web with low contrast.

If you have any additional thoughts, corrections or further research to share, please leave a comment and I’ll amend this article! The fuller our understanding of the needs and requirements of our sites is, the better we can plan improvements and ultimately serve the needs of our audiences.

The post Understanding Web Accessibility Color Contrast Guidelines and Ratios appeared first on CSS-Tricks.

Same HTML, Different CSS

Css Tricks - Wed, 02/19/2020 - 5:35am

Ahmad Shadeed covers the idea of a card component that has a fixed set of semantic HTML with some BEMy classes on it. There is a title, author, image, and tags. Then he redesigns the card into five totally different designs without touching any of the HTML just the CSS.

If this is an ah-ha moment for you, awesome! It might be worth knowing that this exact concept essentially excited an entire generation of front-end developers, in no small part due to the concept of the CSS Zen Garden, where the entire website was a fixed set of HTML and only CSS changes birthed some incredible creativity.

Of course, we typically do get our hands into HTML when doing redesign work, but this is still a fun exercise that drives home the power of CSS. I wonder if JavaScript-powered components are what delivers this awe today, because they have a similar power of abstraction: make changes to a component and see the impact across an entire site. Only instead of the idea being rooted in constraint, there are no constraints.

Direct Link to ArticlePermalink

The post Same HTML, Different CSS appeared first on CSS-Tricks.

Centering a div That Maintains Aspect-Ratio When There’s Body Margin

Css Tricks - Tue, 02/18/2020 - 12:33pm

Andrew Welch had a little CSS challenge the other day to make an ordinary div:

• centered vertically + horizontally
• scales to fit the viewport w/ a margin around it
• maintains an arbitrary aspect ratio
• No JS

There's a video in that tweet if it helps you visualize the challenge. I saw Paul Bakaus blogging about this the other day, too, so it's a thing that comes up!

Mark Huot got fancy applying aspect ratios directly with width/height and creating the margins from subtracting from those dimensions:

CodePen Embed Fallback

Amelia Wattenberger's idea is to set both height/width and max-height/max-width with viewport units, and center it with the classic translate trick:

CodePen Embed Fallback

Eric A. Meyer did the same, only centered with flexbox instead.

Brian Hart used vmin units for the aspect ratio sizing and centered it with flexbox:

CodePen Embed Fallback

Benoît Rouleau did the same but used calc() for the margins in a different unit.

Andrew really likes Jonathan Melville's approach. Most of it is in Tailwind classes so it's a smidge hard for me to understand as I'm not used to looking at code like that yet.

CodePen Embed Fallback

Andrew said he ultimately went with the vmin thing — although I see he's using calc() to subtract vmin units from each other which isn't really necessary unless, I guess, you wanna see the math.

The post Centering a div That Maintains Aspect-Ratio When There’s Body Margin appeared first on CSS-Tricks.

Solving Sticky Hover States with @media (hover: hover)

Css Tricks - Tue, 02/18/2020 - 10:38am

Mezo Istvan does a good job of covering the problem and a solution to it in a blog post on Medium¹.

If you tap on something that has a :hover state but you don't leave the page then, on a mobile device, there is a chance that :hover state "sticks." You'll see this with stuff like jump-links used as tabs or buttons that trigger on-page functionality.

button:hover { border: 3px solid green; /* might stick! */ }

The solution, or trick, is a new(ish) "CSS4" media query that allows you only to apply styles on devices with hover capability.

@media (hover: hover) { button:hover { border: 3px solid green; /* solves sticky problem */ } }

Your typical touch screen mobile device will fail that media query, the style won't apply, and you'll avoid the sticky problem.

Support is solid, so not much worry there.

  1. It almost feels like we have to apologize to linking to things on Medium lately. I have no idea what you're going to experience when you get there. Will you just be able to read it? Will it be a teaser where you have to log in to read more? Will it be behind a paywall? I have no idea. In this case, hopefully, this link post has enough info in it that isn't not blocking you from learning anything.


Direct Link to ArticlePermalink

The post Solving Sticky Hover States with @media (hover: hover) appeared first on CSS-Tricks.

How to Build Vue Components in a WordPress Theme

Css Tricks - Tue, 02/18/2020 - 5:27am

Intrigued by the title and just wanna see some code? Skip ahead.

A few months ago, I was building a WordPress website that required a form with a bunch of fancy conditional fields. Different options and info were required for different choices you could make on the form, and our client needed complete control over all fields 1. In addition, the form needed to appear in multiple places in each page, with slightly different configs.

And the header instance of the form needed to be mutually exclusive with the hamburger menu, so that opening one closes the other.

And the form had text content that was relevant to SEO.

And we wanted the server response to present some cute animated feedback.

(Phew.)

The whole thing felt complex enough that I didn't want to handle all that state manually. I remembered reading Sarah Drasner’s article "Replacing jQuery With Vue.js: No Build Step Necessary” which shows how to replace classic jQuery patterns with simple Vue micro-apps. That seemed like a good place to start, but I quickly realized that things would get messy on the PHP side of WordPress.

What I really needed were reusable components

PHP ? JavaScript

I love the static-first approach of Jamstack tools, like Nuxt, and was looking to do something similar here — send the full content from the server, and progressively enhance on the client side.

But PHP doesn’t have a built-in way to work with components. It does, however, support require-ing files inside other files 2. WordPress has an abstraction of require called get_template_part, that runs relative to the theme folder and is easier to work with. Dividing code into template parts is about the closest thing to components that WordPress provides 3.

Vue, on the other hand, is all about components — but it can only do its thing after the page has loaded and JavaScript is running.

The secret to this marriage of paradigms turns out to be the lesser-known Vue directive inline-template. Its great and wonderful powers allow us to define a Vue component using the markup we already have. It’s the perfect middle ground between getting static HTML from the server, and mounting dynamic DOM elements in the client.

First, the browser gets the HTML, then Vue makes it do stuff. Since the markup is built by WordPress, rather than by Vue in the browser, components can easily use any information that site administrators can edit. And, as opposed to .vue files (which are great for building more app-y things), we can keep the same separation of concerns we use for the whole site — structure and content in PHP, style in CSS, and functionality in JavaScript.

To show how this all fits together, we’re going to build a few features for a recipe blog. First, we’ll add a way for users to rate recipes. Then we’ll build a feedback form based on that rating. Finally, we’ll allow users to filter recipes, based on tags and rating.

We’ll build a few components that share state and live on the same page. To get them to play nicely together — and to make it easy to add additional components in the future — we’ll make the whole page our Vue app, and register components inside it.

Each component will live in its own PHP file and be included in the theme using get_template_part.

Laying the groundwork

There are a few special considerations to take into account when applying Vue to existing pages. The first is that Vue doesn't want you loading scripts inside it — it will send ominous errors to the console if you do. The easiest way to avoid this is to add a wrapper element around the content for every page, then load scripts outside of it (which is already a common pattern for all kinds of reasons). Something like this:

<?php /* header.php */ ?> <body <?php body_class(); ?>> <div id="site-wrapper"> <?php /* footer.php */ ?> </div> <!-- #site-wrapper --> <?php wp_footer(); ?>

The second consideration is that Vue has to be called at the end of body element so that it will load after the rest of the DOM is available to parse. We’ll pass true as the fifth argument  (in_footer) for the wp_enqueue_script  function. Also, to make sure Vue is loaded first, we’ll register it as a dependency of the main script.

<?php // functions.php add_action( 'wp_enqueue_scripts', function() { wp_enqueue_script('vue', get_template_directory_uri() . '/assets/js/lib/vue.js', null, null, true); // change to vue.min.js for production wp_enqueue_script('main', get_template_directory_uri() . '/assets/js/main.js', 'vue', null, true);

Finally, in the main script, we’ll initialize Vue on the site-wrapper element.

// main.js new Vue({ el: document.getElementById('site-wrapper') }) The star rating component

Our single post template currently looks like this:

<?php /* single-post.php */ ?> <article class="recipe"> <?php /* ... post content */ ?> <!-- star rating component goes here --> </article>

We’ll register the star rating component and add some logic to manage it:

// main.js Vue.component('star-rating', { data () { return { rating: 0 } }, methods: { rate (i) { this.rating = i } }, watch: { rating (val) { // prevent rating from going out of bounds by checking it to on every change if (val < 0) this.rating = 0 else if (val > 5) this.rating = 5 // ... some logic to save to localStorage or somewhere else } } }) // make sure to initialize Vue after registering all components new Vue({ el: document.getElementById('site-wrapper') })

We’ll write the component template in a separate PHP file. The component will comprise six buttons (one for unrated, 5 with stars). Each button will contain an SVG with either a black or transparent fill.

<?php /* components/star-rating.php */ ?> <star-rating inline-template> <div class="star-rating"> <p>Rate recipe:</p> <button @click="rate(0)"> <svg><path d="..." :fill="rating === 0 ? 'black' : 'transparent'"></svg> </button> <button v-for="(i in 5) @click="rate(i)"> <svg><path d="..." :fill="rating >= i ? 'black' : 'transparent'"></svg> </button> </div> </star-rating>

As a rule of thumb, I like to give a component’s top element a class name that is identical to that of the component itself. This makes it easy to reason between markup and CSS (e.g. <star-rating> can be thought of as .star-rating).

And now we’ll include it in our page template.

<?php /* single-post.php */ ?> <article class="recipe"> <?php /* post content */ ?> <?php get_template_part('components/star-rating'); ?> </article>

All the HTML inside the template is valid and understood by the browser, except for <star-rating>. We can go the extra mile to fix that by using Vue’s is directive:

<div is="star-rating" inline-template>...</div>

Now let’s say that the maximum rating isn’t necessarily 5, but is controllable by the website’s editor using Advanced Custom Fields, a popular WordPress plugin that adds custom fields for pages, posts and other WordPress content. All we need to do is inject that value as a prop of the component that we’ll call maxRating:

<?php // components/star-rating.php // max_rating is the name of the ACF field $max_rating = get_field('max_rating'); ?> <div is="star-rating" inline-template :max-rating="<?= $max_rating ?>"> <div class="star-rating"> <p>Rate recipe:</p> <button @click="rate(0)"> <svg><path d="..." :fill="rating === 0 ? 'black' : 'transparent'"></svg> </button> <button v-for="(i in maxRating) @click="rate(i)"> <svg><path d="..." :fill="rating >= i ? 'black' : 'transparent'"></svg> </button> </div> </div>

And in our script, let’s register the prop and replace the magic number 5:

// main.js Vue.component('star-rating', { props: { maxRating: { type: Number, default: 5 // highlight } }, data () { return { rating: 0 } }, methods: { rate (i) { this.rating = i } }, watch: { rating (val) { // prevent rating from going out of bounds by checking it to on every change if (val < 0) this.rating = 0 else if (val > maxRating) this.rating = maxRating // ... some logic to save to localStorage or somewhere else } } })

In order to save the rating of the specific recipe, we’ll need to pass in the ID of the post. Again, same idea:

<?php // components/star-rating.php $max_rating = get_field('max_rating'); $recipe_id = get_the_ID(); ?> <div is="star-rating" inline-template :max-rating="<?= $max_rating ?>" recipe-id="<?= $recipe_id ?>"> <div class="star-rating"> <p>Rate recipe:</p> <button @click="rate(0)"> <svg><path d="..." :fill="rating === 0 ? 'black' : 'transparent'"></svg> </button> <button v-for="(i in maxRating) @click="rate(i)"> <svg><path d="..." :fill="rating >= i ? 'black' : 'transparent'"></svg> </button> </div> </div> // main.js Vue.component('star-rating', { props: { maxRating: { // Same as before }, recipeId: { type: String, required: true } }, // ... watch: { rating (val) { // Same as before // on every change, save to some storage // e.g. localStorage or posting to a WP comments endpoint someKindOfStorageDefinedElsewhere.save(this.recipeId, this.rating) } }, mounted () { this.rating = someKindOfStorageDefinedElsewhere.load(this.recipeId) } })

Now we can include the same component file in the archive page (a loop of posts), without any additional setup:

<?php // archive.php if (have_posts()): while ( have_posts()): the_post(); ?> <article class="recipe"> <?php // Excerpt, featured image, etc. then: get_template_part('components/star-rating'); ?> </article> <?php endwhile; endif; ?> The feedback form

The moment a user rates a recipe is a great opportunity to ask for more feedback, so let’s add a little form that appears right after the rating is set.

// main.js Vue.component('feedback-form', { props: { recipeId: { type: String, required: true }, show: { type: Boolean, default: false } }, data () { return { name: '', subject: '' // ... other form fields } } }) <?php // components/feedback-form.php $recipe_id = get_the_ID(); ?> <div is="feedback-form" inline-template recipe-id="<?= $recipe_id ?>" v-if="showForm(recipe-id)"> <form class="recipe-feedback-form" id="feedback-form-<?= $recipe_id ?>"> <input type="text" :id="first-name-<?= $recipe_id ?>" v-model="name"> <label for="first-name-<?= $recipe_id ?>">Your name</label> <?php /* ... */ ?> </form> </div>

Notice that we’re appending a unique string (in this case, recipe-id) to each form element’s ID. This is to make sure they all have unique IDs, even if there are multiple copies of the form on the page.

So, where do we want this form to live? It needs to know the recipe’s rating so it knows it needs to open. We’re just building good ol’ components, so let’s use composition to place the form inside the <star-rating>:

<?php // components/star-rating.php $max_rating = get_field('max_rating'); $recipe_id = get_the_ID(); ?> <div is="star-rating" inline-template :max-rating="<?= $max_rating ?>" recipe-id="<?= $recipe_id ?>"> <div class="star-rating"> <p>Rate recipe:</p> <button @click="rate(0)"> <svg><path d="..." :fill="rating === 0 ? 'black' : 'transparent'"></svg> </button> <button v-for="(i in maxRating) @click="rate(i)"> <svg><path d="..." :fill="rating >= i ? 'black' : 'transparent'"></svg> </button> <?php get_template_part('components/feedback-form'); ?> </div> </div>

If at this point you’re thinking, “We really should be composing both components into a single parent component that handles the rating state,” then please give yourself 10 points and wait patiently.

A small progressive enhancement we can add to make the form usable without JavaScript, is to give it the traditional PHP action and then override it in Vue. We’ll use @submit.prevent to prevent the original action, then run a submit method to send the form data in JavaScript.

<?php // components/feedback-form.php $recipe_id = get_the_ID(); ?> <div is="feedback-form" inline-template recipe-id="<?= $recipe_id ?>"> <form action="path/to/feedback-form-handler.php" @submit.prevent="submit" class="recipe-feedback-form" id="feedback-form-<?= $recipe_id ?>"> <input type="text" :id="first-name-<?= $recipe_id ?>" v-model="name"> <label for="first-name-<?= $recipe_id ?>">Your name</label> <!-- ... --> </form> </div>

Then, assuming we want to use fetch, our submit method can be something like this:

// main.js Vue.component('feedback-form', { // Same as before methods: { submit () { const form = this.$el.querySelector('form') const URL = form.action const formData = new FormData(form) fetch(URL, {method: 'POST', body: formData}) .then(result => { ... }) .catch(error => { ... }) } } })

OK, so what do we want to do in .then and .catch? Let’s add a component that will show real-time feedback for the form’s submit status. First let’s add the state to track sending, success, and failure, and a computed property telling us if we’re pending results.

// main.js Vue.component('feedback-form', { // Same as before data () { return { name: '', subject: '' // ... other form fields sent: false, success: false, ?? error: null } }, methods: { submit () { const form = this.$el.querySelector('form') const URL = form.action const formData = new FormData(form) fetch(URL, {method: 'POST', body: formData}) .then(result => { this.success = true }) .catch(error => { this.error = error }) this.sent = true } } })

To add the markup for each message type (success, failure, pending), we could make another component like the others we’ve built so far. But since these messages are meaningless when the server renders the page, we’re better off rendering them only when necessary. To do this we’re going to place our markup in a native HTML <template> tag, which doesn't render anything in the browser. Then we’ll reference it by id as our component’s template.

<?php /* components/form-status.php */ ?> <template id="form-status-component" v-if="false"> <div class="form-message-wrapper"> <div class="pending-message" v-if="pending"> <img src="<?= get_template_directory_uri() ?>/spinner.gif"> <p>Patience, young one.</p> </div> <div class="success-message" v-else-if="success"> <img src="<?= get_template_directory_uri() ?>/beer.gif"> <p>Huzzah!</p> </div> <div class="success-message" v-else-if="error"> <img src="<?= get_template_directory_uri() ?>/broken.gif"> <p>Ooh, boy. It would appear that: {{ error.text }}</p> </div> </div </template>

Why add v-if="false" at the top, you ask? It’s a tricky little thing. Once Vue picks up the HTML <template>, it will immediately think of it as a Vue <template> and render it. Unless, you guessed it, we tell Vue not to render it. A bit of a hack, but there you have it.

Since we only need this markup once on the page, we’ll include the PHP component in the footer.

<?php /* footer.php */ ?> </div> <!-- #site-wrapper --> <?php get_template_part('components/form-status'); ?> <?php wp_footer(); ?>

Now we’ll register the component with Vue…

// main.js Vue.component('form-status', { template: '#form-status-component' props: { pending: { type: Boolean, required: true }, success: { type: Boolean, required: true }, error: { type: [Object, null], required: true }, } })

…and call it inside our form component:

<?php // components/feedback-form.php $recipe_id = get_the_ID(); ?> <div is="feedback-form" inline-template recipe-id="<?= $recipe_id ?>"> <form action="path/to/feedback-form-handler.php" @submit.prevent="submit" class="recipe-feedback-form" id="feedback-form-<?= $recipe_id ?>"> <input type="text" :id="first-name-<?= $recipe_id ?>" v-model="name"> <label for="first-name-<?= $recipe_id ?>">Your name</label> <?php // ... ?> </form> <form-status v-if="sent" :pending="pending" :success="success" :error="error" /> </div>

Since we registered <form-status> using Vue.component, it's available globally, without specifically including it in the parent’s components: { }.

Filtering recipes

Now that users can personalize some bits of their experience on our blog, we can add all kinds of useful functionality. Specifically, let's allow users to set a minimum rating they want to see, using an input at the top of the page.
The first thing we need is some global state to track the minimum rating set by the user. Since we started off by initializing a Vue app on the whole page, global state will just be data on the Vue instance:

// main.js // Same as before new Vue({ el: document.getElementById('site-wrapper'), data: { minimumRating: 0 } })

And where can we put the controls to change this? Since the whole page is the app, the answer is almost anywhere. For instance, at the top of the archive page:

<?php /* archive.php */ ?> <label for="minimum-rating-input">Only show me recipes I've rated at or above:</label> <input type="number" id="minimum-rating-input" v-model="minimumRating"> <?php if (have_posts()): while ( have_posts()): the_post(); ?> <article class="recipe"> <?php /* Post excerpt, featured image, etc. */ ?> <?php get_template_part('components/star-rating'); ?> </article> <?php endwhile; endif; ?>

As long as it’s inside our site-wrapper and not inside another component, it’ll just work. If we want, we could also build a filtering component that would change the global state. And if we wanted to get all fancy, we could even add Vuex to the mix (since Vuex can’t persist state between pages by default, we could add something like vuex-persist to use localStorage).

So, now we need to hide or show a recipe based on the filter. To do this, we’ll need to wrap the recipe content in its own component, with a v-show directive. It’s probably best to use the same component for both the single page and the archive page. Unfortunately, neither require nor get_template_part can pass parameters into the called file — but we can use global variables:

<?php /* archive.php */ ?> <label for="minimum-rating-input">Only show me recipes I've rated at or above:</label> <input type="number" id="minimum-rating-input" v-model="minimumRating"> <?php $is_archive_item = true; if (have_posts()): while ( have_posts()): the_post(); get_template_part('components/recipe-content'); endwhile; endif; ?>

We can then use $is_archive_item as a global variable inside the PHP component file to check if it is set and true. Since we won’t need to hide the content on the single post page, we’ll conditionally add the v-show directive.

<?php // components/recipe-content.php global $is_archive_item; ?> <div is="recipe-content"> <article class="recipe" <?php if ($is_archive_item): ?> v-show="show" <?php endif; ?> > <?php if ($is_archive_item): the_excerpt(); else the_content(); endif; get_template_part('components/star-rating'); ?> </article> </div>

In this specific example, we could have also tested with  is_archive() inside the component, but in most cases we’ll need to set explicit props.

We’ll need to move the rating state and logic up into the <recipe-content> component so it can know if it needs to hide itself. Inside <star-rating>, we’ll make a custom v-model by replacing rating with value, and this.rating = i with  $emit('input', i) as well . So our component registration will now look like this:

// main.js Vue.component('recipe-content', { data () { rating: 0 }, watch: { rating (val) { // ... } }, mounted () { this.rating = someKindOfStorageDefinedElsewhere.load(this.recipeId) } }) Vue.component('star-rating', { props: { maxRating: { /* ... */ }, recipeId: { /* ... */ }, value: { type: Number, required: true } }, methods: { rate (i) { this.$emit('input', i) } }, })

We’ll add v-model in star-rating.php and change rating to value. In addition, we can now move the <feedback-form> up into <recipe-content>:

<?php // components/star-rating.php $max_rating = get_field('max_rating'); $recipe_id = get_the_ID(); ?> <div is="star-rating" inline-template :max-rating="<?= $ max_rating ?>" recipe-id="<?= $recipe_id ?>" v-model="value" > <div class="star-rating"> <p>Rate recipe:</p> <button @click="rate(0)"> <svg><path d="..." :fill="value === 0 ? 'black' : 'transparent'"></svg> </button> <button v-for="(i in maxRating) @click="rate(i)"> <svg><path d="..." :fill="value >= i ? 'black' : 'transparent'"></svg> </button> </div> </div> <?php // components/recipe-content.php global $is_archive_item; ?> <div is="recipe-content"> <article class="recipe" <?php if ($is_archive_item): ?> v-show="show" <?php endif; ?> > <?php if ($is_archive_item): the_excerpt(); else the_content(); endif; get_template_part('components/star-rating'); get_template_part('components/feedback-form'); ?> </article> </div>

Now everything is set up so the initial render shows all recipes, and then the user can filter them based on their rating. Moving forward, we could add all kinds of parameters to filter content. And it doesn’t have to be based on user input — we can allow filtering based on the content itself (e.g. number of ingredients or cooking time) by passing the data from PHP to Vue.

Conclusion

Well, that was a bit of a long ride, but look at what we’ve built: independent, composable, maintainable, interactive, progressively enhanced components in our WordPress theme. We brought together the best of all worlds!

I’ve been using this approach in production for a while now, and I love the way it allows me to reason about the different parts of my themes. I hope I’ve inspired you to try it out too.

  1. Of course, two days before launch, the client’s legal department decided they don't want to collect all that info. Currently the live form is but a shadow of its development self.
  2. Fun fact: Rasmus Lerdorf said that his original intent was for PHP to be templating only, with all business logic handled in C. Let that sink in for a moment. Then clear an hour from your schedule and watch the whole talk.
  3. There are third-party WordPress templating engines that can compile down to optimized PHP. Twig, for example, comes to mind. We’re trying to go the reverse route and send vanilla PHP to be handled by JavaScript.

The post How to Build Vue Components in a WordPress Theme appeared first on CSS-Tricks.

Web Component for a Code Block

Css Tricks - Tue, 02/18/2020 - 5:27am

We'll get to that, but first, a long-winded introduction.

I'm still not in a confident place knowing a good time to use native web components. The templating isn't particularly robust, so that doesn't draw me in. There is no state management, and I like having standard ways of handling that. If I'm using another library for components anyway, seems like I would just stick with that. So, at the moment, my checklist is something like:

  • Not using any other JavaScript framework that has components
  • Templating needs aren't particularly complex
  • Don't need particularly performant re-rendering
  • Don't need state management

I'm sure there is tooling that helps with these things and more (the devMode episode with some folks from Stencil was good), but if I'm going to get into tooling-land, I'd be extra tempted to go with a framework, and probably not framework plus another thing with a lot of overlap.

The reasons I am tempted to go with native web components are:

  • They are native. No downloads of frameworks.
  • The Shadow DOM is a true encapsulation in a way a framework can't really do.
  • I get to build my own HTML element that I use in HTML, with my own API design.

It sorta seems like the sweet spot for native web components is design system components. You build out your own little API for the components in your system, and people can use them in a way that is a lot safer than just copy and paste this chunk of HTML. And I suppose if consumers of the system wanted to BYO framework, they could.

So you can use like <our-tabs active-tab="3"> rather than <div class="tabs"> ... <a href="#3" class="tab-is-active">. Refactoring the components certainly gets a lot easier as changes percolate everywhere.

I've used them here on CSS-Tricks for our <circle-text> component. It takes the radius as a parameter and the content via, uh, content, and outputs an <svg> that does the trick. It gave us a nice API for authoring that abstracted away the complexity.

So!

It occurred to me a "code block" might be a nice use-case for a web component.

  • The API would be nice for it, as you could have attributes control useful things, and the code itself as the content (which is a great fallback).
  • It doesn't really need state.
  • Syntax highlighting is a big gnarly block of CSS, so it would be kinda cool to isolate that away in the Shadow DOM.
  • It could have useful functionality like a "click to copy" button that people might enjoy having.

Altogether, it might feel like a yeah, I could use this kinda component.

This probably isn't really production ready (for one thing, it's not on npm or anything yet), but here's where I am so far:

CodePen Embed Fallback

Here's a thought dump!

  • What do you do when a component depends on a third-party lib? The syntax highlighting here is done with Prism.js. To make it more isolated, I suppose you could copy and paste the whole lib in there somewhere, but that seems silly. Maybe you just document it?
  • Styling web components doesn't feel like it has a great story yet, despite the fact that Shadow DOM is cool and useful.
  • Yanking in pre-formatted text to use in a template is super weird. I'm sure it's possible to do without needing a <pre> tag inside the custom element, but it's clearly much easier if you grab the content from the <pre>. Makes the API here just a smidge less friendly (because I'd prefer to use the <code-block> alone).
  • I wonder what a good practice is for passing along attributes that another library needs. Like is data-lang="CSS" OK to use (feels nicer), and then convert it to class="language-css" in the template because that's what Prism wants? Or is it better practice to just pass along attributes as they are? (I went with the latter.)
  • People complain that there aren't really "lifecycle methods" in native web components, but at least you have one: when the thing renders: connectedCallback. So, I suppose you should do all the manipulation of HTML and such before you do that final shadowRoot.appendChild(node);. I'm not doing that here, and instead am running Prism over the whole shadowRoot after it's been appended. Just seemed to work that way. I imagine it's probably better, and possible, to do it ahead of time rather than allow all the repainting caused by injecting spans and such.
  • The whole point of this is a nice API. Seems to me thing would be nicer if it was possible to drop un-escaped HTML in there to highlight and it could escape it for you. But that makes the fallback actually render that HTML which could be bad (or even theoretically insecure). What's a good story for that? Maybe put the HTML in HTML comments and test if <!-- is the start of the content and handle that as a special situation?

Anyway, if you wanna fork it or do anything fancier with it, lemme know. Maybe we can eventually put it on npm or whatever. We'll have to see how useful people think it could be.

The post Web Component for a Code Block appeared first on CSS-Tricks.

A Complete Guide to Data Attributes

Css Tricks - Mon, 02/17/2020 - 2:07pm
Table of Contents
  1. Introduction
  2. Syntax
  3. Styling with data attributes
  4. Accessing data attributes in JavaScript
Introduction

HTML elements can have attributes on them that are used for anything from accessibility information to stylistic control.

<!-- We can use the `class` for styling in CSS, and we've also make this into a landmark region --> <div class="names" role="region" aria-label="Names"></div>

What is discouraged is making up your own attributes, or repurposing existing attributes for unrelated functionality.

<!-- `highlight` is not an HTML attribute --> <div highlight="true"></div> <!-- `large` is not a valid value of `width` --> <div width="large">

There are a variety of reasons this is bad. Your HTML becomes invalid, which may not have any actual negative consequences, but robs you of that warm fuzzy valid HTML feeling. The most compelling reason is that HTML is a living language and just because attributes and values that don't do anything today doesn't mean they never will.

Good news though: you can make up your own attributes. You just need to prefix them with data-* and then you're free to do what you please!

Syntax

It can be awfully handy to be able to make up your own HTML attributes and put your own information inside them. Fortunately, you can! That's exactly what data attributes are. They are like this:

<!-- They don't need a value --> <div data-foo></div> <!-- ...but they can have a value --> <div data-size="large"></div> <!-- You're in HTML here, so careful to escape code if you need to do something like put more HTML inside --> <li data-prefix="Careful with HTML in here."><li> <!-- You can keep dashing if you like --> <aside data-some-long-attribute-name><aside>

Data attributes are often referred to as data-* attributes, as they are always formatted like that. The word data, then a dash -, then other text you can make up.

Can you use the data attribute alone? <div data=""></div>

It's probably not going to hurt anything, but you won't get the JavaScript API we'll cover later in this guide. You're essentially making up an attribute for yourself, which as I mentioned in the intro, is discouraged.

What not to do with data attributes

Store content that should be accessible. If the content should be seen or read on a page, don't only put them in data attributes, but make sure that content is in the HTML content somewhere.

<!-- This isn't accessible content --> <div data-name="Chris Coyier"></div> <!-- If you need programmatic access to it but shouldn't be seen, there are other ways... --> <div> <span class="visually-hidden">Chris Coyier</span> </div>

Here's more about hiding things.

Styling with data attributes

CSS can select HTML elements based on attributes and their values.

/* Select any element with this data attribute and value */ [data-size="large"] { padding: 2rem; font-size: 125%; } /* You can scope it to an element or class or anything else */ button[data-type="download"] { } .card[data-pad="extra"] { }

This can be compelling. The predominant styling hooks in HTML/CSS are classes, and while classes are great (they have medium specificity and nice JavaScript methods via classList) an element either has it or it doesn't (essentially on or off). With data-* attributes, you get that on/off ability plus the ability to select based on the value it has at the same specificity level.

/* Selects if the attribute is present at all */ [data-size] { } /* Selects if the attribute has a particular value */ [data-state="open"], [aria-expanded="true"] { } /* "Starts with" selector, meaning this would match "3" or anything starting with 3, like "3.14" */ [data-version^="3"] { } /* "Contains" meaning if the value has the string anywhere inside it */ [data-company*="google"] { } The specificity of attribute selectors

It's the exact same as a class. We often think of specificity as a four-part value:

inline style, IDs, classes/attributes, tags

So a single attribute selector alone is 0, 0, 1, 0. A selector like this:

div.card[data-foo="bar"] { }

...would be 0, 0, 2, 1. The 2 is because there is one class (.card) and one attribute ([data-foo="bar"]), and the 1 is because there is one tag (div).

Attribute selectors have less specificity than an ID, more than an element/tag, and the same as a class.

Case-insensitive attribute values

In case you're needing to correct for possible capitalization inconsistencies in your data attributes, the attribute selector has a case-insensitive variant for that.

/* Will match <div data-state="open"></div> <div data-state="Open"></div> <div data-state="OPEN"></div> <div data-state="oPeN"></div> */ [data-state="open" i] { }

It's the little i within the bracketed selector.

Using data attributes visually

CSS allows you to yank out the data attribute value and display it if you need to.

/* <div data-emoji="✅"> */ [data-emoji]::before { content: attr(data-emoji); /* Returns '✅' */ margin-right: 5px; } Example styling use-case

You could use data attributes to specify how many columns you want a grid container to have.

<div data-columns="2"></div> <div data-columns="3"></div> <div data-columns="4"></div> CodePen Embed Fallback Accessing data attributes in JavaScript

Like any other attribute, you can access the value with the generic method getAttribute.

let value = el.getAttribute("data-state"); // You can set the value as well. // Returns data-state="collapsed" el.setAttribute("data-state", "collapsed");

But data attributes have their own special API as well. Say you have an element with multiple data attributes (which is totally fine):

<span data-info="123" data-index="2" data-prefix="Dr. " data-emoji-icon="&#x1f3cc;️‍♀️" ></span>

If you have a reference to that element, you can set and get the attributes like:

// Get span.dataset.info; // 123 span.dataset.index; // 2 // Set span.dataset.prefix = "Mr. "; span.dataset.emojiIcon = "&#x1f3aa;";

Note the camelCase usage on the last line there. It automatically converts kebab-style attributes in HTML, like data-this-little-piggy, to camelCase style in JavaScript, like dataThisLittlePiggy.

This API is arguably not quite as nice as classList with the clear add, remove, toggle, and replace methods, but it's better than nothing.

You have access to inline datasets as well:

<img src="spaceship.png" data-ship-id="324" data-shields="72%" onclick="pewpew(this.dataset.shipId)"> </img> JSON data inside data attributes <ul> <li data-person=' { "name": "Chris Coyier", "job": "Web Person" } '></li> </ul>

Hey, why not? It's just a string and it's possible to format it as valid JSON (mind the quotes and such). You can yank that data and parse it as needed.

const el = document.querySelector("li"); let json = el.dataset.person; let data = JSON.parse(json); console.log(data.name); // Chris Coyier console.log(data.job); // Web Person JavaScript use-cases

The concept is that you can use data attributes to put information in HTML that JavaScript may need access to do certain things.

A common one would have to do with database functionality. Say you have a "Like" button:

<button data-id="435432343">?</button>

That button could have a click handler on it which performs an Ajax request to the server to increment the number of likes in a database on click. It knows which record to update because it gets it from the data attribute.

Specifications Browser support

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

DesktopChromeFirefoxIEEdgeSafari7611125.1Mobile / TabletAndroid ChromeAndroid FirefoxAndroidiOS Safari796835.0-5.1

The post A Complete Guide to Data Attributes appeared first on CSS-Tricks.

Moving from Vanilla JavaScript to a Reusable Vue Component

Css Tricks - Mon, 02/17/2020 - 5:42am

I recently wrote an article explaining how you can create a countdown timer using HTML, CSS and JavaScript. Now, let’s look at how we can make that a reusable component by porting it into Vue using basic features that the framework provides.

Why do this at all? Well there are few reasons, but two stand out in particular:

  • Keeping UI in sync with the timer state: If you look at the code from the first post,  it all lives in the timerInterval function, most noticeably the state management. Each time it runs (every second) we need to manually find the proper element on our document — whether it’s the time label or the remaining time path or whatever — and change either its value or an attribute. Vue comes with an HTML-based template syntax that allows you to declaratively bind the rendered DOM to the underlying Vue instance’s data. That takes all the burden of finding and updating proper UI elements so we can rely purely on the component instance’s properties.
  • Having a highly reusable component: The original example works fine when only one timer is present on our document, but imagine that you want to add another one. Oops! We rely the element’s ID to perform our actions and using the same ID on multiple instances would prevent them from working independently. That means we would have to assign different IDs for each timer. If we create a Vue component, all it’s logic is encapsulated and connected to that specific instance of the component. We can easily create 10, 20, 1,000 timers on a single document without changing a single line in the component itself!

Here’s the same timer we created together in the last post, but in Vue.

Template and styles

From the Vue docs:

Vue uses an HTML-based template syntax that allows you to declaratively bind the rendered DOM to the underlying Vue instance’s data. All Vue.js templates are valid HTML that can be parsed by spec-compliant browsers and HTML parsers.

Let’s create our component by opening a new file called BaseTimer.vue. Here’s the basic structure we need for that:

// Our template markup will go here <template> // ... </template> // Our functional scripts will go here <script> // ... </script> // Our styling will go here <style> // ... </style>

In this step, we will concentrate on the <template> and <style> sections. Let’s move our timer template to the <template> section and all our CSS to <style> section. The markup mostly consists of SVG and we can use the exact same code we used from the first article.

<template> // The wrapper for the timer <div class="base-timer"> // This all comes from the first article <svg class="base-timer__svg" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> <g class="base-timer__circle"> <circle class="base-timer__path-elapsed" cx="50" cy="50" r="45"></circle> <path id="base-timer-path-remaining" stroke-dasharray="283" class="base-timer__path-remaining ${remainingPathColor}" d=" M 50, 50 m -45, 0 a 45,45 0 1,0 90,0 a 45,45 0 1,0 -90,0 " ></path> </g> </svg> // The label showing the remaining time <span id="base-timer-label" class="base-timer__label" > ${formatTime(timeLeft)} </span> </div> </template> // "scoped" means these styles will not leak out to other elements on the page <style scoped> .base-timer { position: relative; width: 100px; height: 100px; } </style>

Let’s have a look at the template we just copied to identify where we can use our framework. There are few parts that are responsible for making our timer count down the time and show the remaining time.

  • stroke-dasharray: A value passed to the SVG <path> element that is responsible for holding the remaining time.
  • remainingPathColor: A CSS class responsible for changing the color of the timer’s circular ring, giving is a way to visually indicate that time is running out.
  • formatTime(timeLeft): A value responsible for showing how much time is left inside the timer

We can control our timer by manipulating those values.

Constants and variables

OK, let’s go down to our <script> section and see what Vue gives us out of the box to make our life easier. One thing it lets us do is define our constants up front, which keeps them scoped to the component.

In the last post, we spent a little time tweaking the stroke-dasharray  value to make sure the animation of the timer’s top layer (the ring that animates and changes color as time progresses) is perfectly in line with its bottom layer (the gray ring that indicates past time). We also defined “thresholds” for when the top layer should change colors (orange at 10 remaining seconds and red at five seconds). We also created constants for those colors.

We can move all of those directly into the <script> section:

<script> // A value we had to play with a bit to get right const FULL_DASH_ARRAY = 283; // When the timer should change from green to orange const WARNING_THRESHOLD = 10; // When the timer should change from orange to red const ALERT_THRESHOLD = 5; // The actual colors to use at the info, warning and alert threshholds const COLOR_CODES = { info: { color: "green" }, warning: { color: "orange", threshold: WARNING_THRESHOLD }, alert: { color: "red", threshold: ALERT_THRESHOLD } }; // The timer's starting point const TIME_LIMIT = 20; </script>

Now, let’s have a look at our variables:

let timePassed = 0; let timeLeft = TIME_LIMIT; let timerInterval = null; let remainingPathColor = COLOR_CODES.info.color;

We can identify two different types of variables here:

  1. Variables in which the values are directly re-assigned in our methods:
    • timerInterval: Changes when we start or stop the timer
    • timePassed: Changes each second when the timer is running
  2. Variables in which the values change when other variables change:
    • timeLeft: Changes when the value of timePassed changes
    • remainingPathColor: Changes when the value of timeLeft breaches the specified threshold

It is essential to identify that difference between those two types as it allows us to use different features of the framework. Let’s go through each of the type separately.

Variables in which values are directly re-assigned

Let’s think what we want to happen when we change the timePassed value. We want to calculate how much time is left, check if we should change the top ring’s color, and trigger re-render on a part of our view with new values. 

Vue comes with its own reactivity system that updates the view to match the new values of specific properties. To add a property to Vue’s reactivity system we need to declare that property on a data object in our component. By doing that,Vue will create a getter and a setter for each property that will track changes in that property and respond accordingly.

<script> // Same as before export default { data() { return { timePassed: 0, timerInterval: null }; } </script>

There are two important things we need to remember.

  1. We need to declare all reactive variables in our data object up front. That means if we know that a variable will exist but we don’t know what the value will be, we still need to declare it with some value. If we forgot to declare it in data it will not be reactive, even if it is added later.
  2. When declaring our data option object, we always need to return a new object instance (using return). This is vital because, if we don’t follow this rule, the declared properties will be shared between all instances of the component.

You can see that second issue in action:

Variables in which values change when other variable change

These variables rely on the value of another variable. For example, timeLeft relies purely on timePassed. In our original example that uses vanilla JavaScript, we were calculating that value in the interval that was responsible for changing the value of timePassed. With Vue, we can extract that value to a computed property.

A computed property is a function that returns a value. These values are bound to the dependency values and only update when required. Even more importantly, computed properties are cached, meaning they remember the values that the computed property depends on and calculate the new value only if that dependent property value changed. If the value does not change, the previously cached value is returned.

<script> // Same as before computed: { timeLeft() { return TIME_LIMIT - this.timePassed; } } } </script>

The function passed to the computed property must be a pure function. It can’t cause any side effects and must return a value. Also, the output value must only be dependent on the values passed into the function.

Now, we can move more logic to computed properties:

  • circleDasharray: This returns a value previously that is calculated in the setCircleDasharray method.
  • formattedTimeLeft: This returns a value from the formatTime method.
  • timeFraction: This is an abstraction of the calculateTimeFraction method.
  • remainingPathColor: This is an abstraction of the setRemainingPathColor method.
<script> // Same as before computed: { circleDasharray() { return `${(this.timeFraction * FULL_DASH_ARRAY).toFixed(0)} 283`; }, formattedTimeLeft() { const timeLeft = this.timeLeft; const minutes = Math.floor(timeLeft / 60); let seconds = timeLeft % 60; if (seconds < 10) { seconds = `0${seconds}`; } return `${minutes}:${seconds}`; }, timeLeft() { return TIME_LIMIT - this.timePassed; }, timeFraction() { const rawTimeFraction = this.timeLeft / TIME_LIMIT; return rawTimeFraction - (1 / TIME_LIMIT) * (1 - rawTimeFraction); }, remainingPathColor() { const { alert, warning, info } = COLOR_CODES; if (this.timeLeft <= alert.threshold) { return alert.color; } else if (this.timeLeft <= warning.threshold) { return warning.color; } else { return info.color; } } } </script>

We now have all the values we need! But now we need to put them to use in our template.

Using data and computed properties in the template

Here’s where we left off with our template:

<template> <div class="base-timer"> <svg class="base-timer__svg" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> <g class="base-timer__circle"> <circle class="base-timer__path-elapsed" cx="50" cy="50" r="45"></circle> <path id="base-timer-path-remaining" stroke-dasharray="283" class="base-timer__path-remaining ${remainingPathColor}" d=" M 50, 50 m -45, 0 a 45,45 0 1,0 90,0 a 45,45 0 1,0 -90,0 " ></path> </g> </svg> <span id="base-timer-label" class="base-timer__label" > ${formatTime(timeLeft)} </span> </div> </template>

Let’s start with formatTime(timeLeft). How we can dynamically bind the rendered value to our formattedTimeLeftcomputed property?

Vue uses HTML-based template syntax that allowsus to declaratively bind the rendered DOM to the underlying data of the Vue instance. That means all properties are available in the template section. To render any of them, we use text interpolation using the “Mustache” syntax (double curly braces, or {{ }}).

<span id="base-timer-label" class="base-timer__label" > {{ formattedTimeLeft }} </span>

Next will be stroke-dasharray. We can see we don’t want to render that value. Instead, we want to change the value of the <path> attribute. Mustache cannot be used inside HTML attributes, but fear not! Vue comes with another way: the v-bind directive. We can bind a value to an attribute like this:

<path v-bind:stroke-dasharray="circleDasharray"></path>

To facilitate the usage of that directive, we can also use a shorthand.

<path :stroke-dasharray="circleDasharray"></path>

The last one is remainingPathColor, which adds a proper class to an element. We can do that using the same v-bind directive as above, but assign the value to the class attribute of an element.

<path :class="remainingPathColor"></path>

Let’s have a look at our template after changes.

<template> <div class="base-timer"> <svg class="base-timer__svg" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> <g class="base-timer__circle"> <circle class="base-timer__path-elapsed" cx="50" cy="50" r="45"></circle> <path :stroke-dasharray="circleDasharray" class="base-timer__path-remaining" :class="remainingPathColor" d=" M 50, 50 m -45, 0 a 45,45 0 1,0 90,0 a 45,45 0 1,0 -90,0 " ></path> </g> </svg> <span class="base-timer__label">{{ formattedTimeLeft }}</span> </div> </template>

We have our template ready, we moved all variables to data or computed, and we got rid off most of the methods by creating corresponding computed properties. We are still missing one vital part, though: we need to start our timer.

Methods and component lifecycle hooks

If we look at our startTimer method, we can see that all the calculations, changes in attributes, etc. happen in the interval.

function startTimer() { timerInterval = setInterval(() => { timePassed = timePassed += 1; timeLeft = TIME_LIMIT - timePassed; document.getElementById("base-timer-label").innerHTML = formatTime( timeLeft ); setCircleDasharray(); setRemainingPathColor(timeLeft); if (timeLeft === 0) { onTimesUp(); } }, 1000); }

Since we’ve already moved all that logic into the computed property, all we need to do in our timerInterval is change the value of timePassed — the rest will happen magically in the computed properties

<script> // Same as before methods: { startTimer() { this.timerInterval = setInterval(() => (this.timePassed += 1), 1000); } } </script>

We have the method ready, but we still don’t call it anywhere. Each Vue component comes with a series of hooks that allows us to run a specific logic within a specific period of the component’s lifecycle. These are called lifecycle hooks. In our case, as we want to call our method immediately when the component gets loaded. That makes mounted the lifecycle hook what we want.

<script> // Same as before mounted() { this.startTimer(); }, // Same methods as before </script>

That’s it, we just turned our timer into a consistent and reusable component using Vue!

Let's say we now want to use this component in another component. That requires a few things:

  1. First, we import the component.
  2. Next, we register the component.
  3. Finally, we instantiate the component in the template.
// App.vue import BaseTimer from "./components/BaseTimer" export default { components: { BaseTimer } }; That’s a wrap!

This example shows how we can move a component from vanilla JavaScript to a component-based front-end framework, like Vue. 

We can now treat the timer as a standalone component where all the markup, logic and styling is contained in a way that won’t leak out to or conflict with other elements. Components are often children of a larger parent component that assembles multiple components together — like a form or perhaps a card — where the parent’s properties can be accessed and shared. Here’s an example of the timer component where it’s taking orders from a parent component

I hope I got you interested in Vue and the power of components! I’d encourage you to go to Vue docs to get more detailed description of the features we used in our example. There’s so much Vue can do!

The post Moving from Vanilla JavaScript to a Reusable Vue Component appeared first on CSS-Tricks.

Blame the implementation, not the technique

Css Tricks - Mon, 02/17/2020 - 5:42am

I'm not sure we've gotten much better at this since Tim Kadlec wrote this in 2012:

Stop me if you’ve heard this one before.

“Responsive design is bad for performance.”
“User agent detection is bad. Don’t segment the web.”
“Hybrid apps don’t work as well as native apps.”
“CSS preprocessors shouldn’t be used because they create bloated CSS.”

... Find out for yourself if the tool is really where the blame should be placed.

I'm sure there is some psychological concept that explains why we transfer blame from the offending thing to what we perceive to be the cause.

Sometimes we're good at this. Remember the AMP letter:

The AMP format is not in itself, a problem, but two aspects of its implementation...

Or the fact that accessibility issues aren't React's fault. Pointing at the tools makes it harder to talk about the real problems that need to be resolved.

Sometimes I'm not so good at this. I'm linking to Tim here in an effort to help me remember this.

Direct Link to ArticlePermalink

The post Blame the implementation, not the technique appeared first on CSS-Tricks.

Listen to your web pages

Css Tricks - Sun, 02/16/2020 - 10:50am

A clever idea from Tom Hicks combining MutationObserver (which can "observe" changes to elements like when their attributes, text, or children change) and the Web Audio API for creating sounds. Plop this code into the console on a page where you'd like to listen to essentially any DOM change to hear it doing stuff.

I played with it on my serverless site because it's an SPA so there is plenty of DOM activity as you navigate around.

const audioCtx = new (window.AudioContext || window.webkitAudioContext)() const observer = new MutationObserver(function(mutationsList) { const oscillator = audioCtx.createOscillator() oscillator.connect(audioCtx.destination) oscillator.type = "sine" oscillator.frequency.setValueAtTime( Math.log(mutationsList.length + 5) * 880, audioCtx.currentTime, ) oscillator.start() oscillator.stop(audioCtx.currentTime + 0.01) }) observer.observe(document, { attributes: true, childList: true, subtree: true, characterData: true, })

Looks like Tom is experimenting with other audio... what should we call them? Auralizations? Like this sweep-swoop one. There is already a browser extension for it, which includes sounds for network activity happening.

Direct Link to ArticlePermalink

The post Listen to your web pages appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.