Animated Background Stripes That Transition on Hover

How often to do you reach for the CSS background-size property? If you’re like me — and probably lots of other front-end folks — then it’s usually when you background-size: cover an image to fill the space of an entire element.

Well, I was presented with an interesting challenge that required more advanced background sizing: background stripes that transition on hover. Check this out and hover it with your cursor:

There’s a lot more going on there than the size of the background, but that was the trick I needed to get the stripes to transition. I thought I’d show you how I arrived there, not only because I think it’s a really nice visual effect, but because it required me to get creative with gradients and blend modes that I think you might enjoy.

Let’s start with a very basic setup to keep things simple. I’m talking about a single <div> in the HTML that’s styled as a green square:

<div></div>
div {
  width: 500px;
  height: 500px;
  background: palegreen;
}
Perfect square with a pale green background color.

Setting up the background stripes

If your mind went straight to a CSS linear gradient when you saw those stripes, then we’re already on the same page. We can’t exactly do a repeating gradient in this case since we want the stripes to occupy uneven amounts of space and transition them, but we can create five stripes by chaining five backgrounds on top of our existing background color and placing them to the top-right of the container:

div {
  width: 500px;
  height: 500px;
  background: 
    linear-gradient(black, black) top right,
    linear-gradient(black, black) top 100px right,
    linear-gradient(black, black) top 200px right,
    linear-gradient(black, black) top 300px right,
    linear-gradient(black, black) top 400px right, 
    palegreen;
}

I made horizontal stripes, but we could also go vertical with the approach we’re covering here. And we can simplify this quite a bit with custom properties:

div {
  --gt: linear-gradient(black, black);
  --n: 100px;

  width: 500px;
  height: 500px;
  background: 
    var(--gt) top right,
    var(--gt) top var(--n) right,
    var(--gt) top calc(var(--n) * 2) right,
    var(--gt) top calc(var(--n) * 3) right,
    var(--gt) top calc(var(--n) * 4) right, 
    palegreen;
}

So, the --gt value is the gradient and --n is a constant we’re using to nudge the stripes downward so they are offset vertically. And you may have noticed that I haven’t set a true gradient, but rather solid black stripes in the linear-gradient() function — that’s intentional and we’ll get to why I did that in a bit.

One more thing we ought to do before moving on is prevent our backgrounds from repeating; otherwise, they’ll tile and fill the entire space:

div {
  --gt: linear-gradient(black, black);
  --n: 100px;

  width: 500px;
  height: 500px;
  background: 
    var(--gt) top right,
    var(--gt) top var(--n) right,
    var(--gt) top calc(var(--n) * 2) right,
    var(--gt) top calc(var(--n) * 3) right,
    var(--gt) top calc(var(--n) * 4) right, 
    palegreen;
  background-repeat: no-repeat;
}

We could have set background-repeat in the background shorthand, but I decided to break it out here to keep things easy to read.

Offsetting the stripes

We technically have stripes, but it’s pretty tough to tell because there’s no spacing between them and they cover the entire container. It’s more like we have a solid black square.

This is where we get to use the background-size property. We want to set both the height and the width of the stripes and the property supports a two-value syntax that allows us to do exactly that. And, we can chain those sizes by comma separating them the same way we did on background.

Let’s start simple by setting the widths first. Using the single-value syntax for background-size sets the width and defaults the height to auto. I’m using totally arbitrary values here, so set the values to what works best for your design:

div {
  --gt: linear-gradient(black, black);
  --n: 100px;

  width: 500px;
  height: 500px;
  background: 
    var(--gt) top right,
    var(--gt) top var(--n) right,
    var(--gt) top calc(var(--n) * 2) right,
    var(--gt) top calc(var(--n) * 3) right,
    var(--gt) top calc(var(--n) * 4) right, 
    palegreen;
  background-repeat: no-repeat;
  background-size: 60%, 90%, 70%, 40%, 10%;
}

If you’re using the same values that I am, you’ll get this:

Doesn’t exactly look like we set the width for all the stripes, does it? That’s because of the auto height behavior of the single-value syntax. The second stripe is wider than the others below it, and it is covering them. We ought to set the heights so we can see our work. They should all be the same height and we can actually re-use our --n variable, again, to keep things simple:

div {
  --gt: linear-gradient(black, black);
  --n: 100px;

  width: 500px;
  height: 500px;
  background: 
    var(--gt) top right,
    var(--gt) top var(--n) right,
    var(--gt) top calc(var(--n) * 2) right,
    var(--gt) top calc(var(--n) * 3) right,
    var(--gt) top calc(var(--n) * 4) right, 
    palegreen;
    background-repeat: no-repeat;
    background-size: 60% var(--n), 90% var(--n), 70% var(--n), 40% var(--n), 10% var(--n); // HIGHLIGHT 15
}

Ah, much better!

Adding gaps between the stripes

This is a totally optional step if your design doesn’t require gaps between the stripes, but mine did and it’s not overly complicated. We change the height of each stripe’s background-size a smidge, decreasing the value so they fall short of filling the full vertical space.

We can continue to use our --n variable, but subtract a small amount, say 5px, using calc() to get what we want.

background-size: 60% calc(var(--n) - 5px), 90% calc(var(--n) - 5px), 70% calc(var(--n) - 5px), 40% calc(var(--n) - 5px), 10% calc(var(--n) - 5px);

That’s a lot of repetition we can eliminate with another variable:

div {
  --h: calc(var(--n) - 5px);
  /* etc. */
  background-size: 60% var(--h), 90% var(--h), 70% var(--h), 40% var(--h), 10% var(--h);
}

Masking and blending

Now let’s swap the palegreen background color we’ve been using for visual purposes up to this point for white.

div {
  /* etc. */
  background: 
    var(--gt) top right,
    var(--gt) top var(--n) right,
    var(--gt) top calc(var(--n) * 2) right,
    var(--gt) top calc(var(--n) * 3) right,
    var(--gt) top calc(var(--n) * 4) right, 
    #fff;
  /* etc. */
}

A black and white pattern like this is perfect for masking and blending. To do that, we’re first going to wrap our <div> in a new parent container and introduce a second <div> under it:

<section>
  <div></div>
  <div></div>
</section>

We’re going to do a little CSS re-factoring here. Now that we have a new parent container, we can pass the fixed width and height properties we were using on our <div> over there:

section {
  width: 500px;
  height: 500px;
} 

I’m also going to use CSS Grid to position the two <div> elements on top of one another. This is the same trick Temani Afif uses to create his super cool image galleries. The idea is that we place both divs over the full container using the grid-area property and align everything toward the center:

section {
  display: grid;
  align-items: center;
  justify-items: center;
  width: 500px;
  height: 500px;
} 

section > div {
  width: inherit;
  height: inherit;
  grid-area: 1 / 1;
}

Now, check this out. The reason I used a solid gradient that goes from black to black earlier is to set us up for masking and blending the two <div> layers. This isn’t true masking in the sense that we’re calling the mask property, but the contrast between the layers controls what colors are visible. The area covered by white will remain white, and the area covered by black leaks through. MDN’s documentation on blend modes has a nice explanation of how this works.

To get that working, I’ll apply the real gradient we want to see on the first <div> while applying the style rules from our initial <div> on the new one, using the :nth-child() pseudo-selector:

div:nth-child(1) { 
  background: linear-gradient(to right, red, orange); 
}

div:nth-child(2)  {
  --gt: linear-gradient(black, black);
  --n: 100px;
  --h: calc(var(--n) - 5px);
  background: 
    var(--gt) top right,
    var(--gt) top var(--n) right,
    var(--gt) top calc(var(--n) * 2) right,
    var(--gt) top calc(var(--n) * 3) right,
    var(--gt) top calc(var(--n) * 4) right, 
    white;
  background-repeat: no-repeat;
  background-size: 60% var(--h), 90% var(--h), 70% var(--h), 40% var(--h), 10% var(--h);
}

If we stop here, we actually won’t see any visual difference from what we had before. That’s because we haven’t done the actual blending yet. So, let’s do that now using the screen blend mode:

div:nth-child(2)  {
  /* etc. */
  mix-blend-mode: screen;
}

I used a beige background color in the demo I showed at the beginning of this article. That slightly darker sort of off-white coloring allows a little color to bleed through the rest of the background:

The hover effect

The last piece of this puzzle is the hover effect that widens the stripes to full width. First, let’s write out our selector for it. We want this to happen when the parent container (<section> in our case) is hovered. When it’s hovered, we’ll change the background size of the stripes contained in the second <div>:

/* When <section> is hovered, change the second div's styles */
section:hover > div:nth-child(2){
  /* styles go here */
}

We’ll want to change the background-size of the stripes to the full width of the container while maintaining the same height:

section:hover > div:nth-child(2){
  background-size: 100% var(--h);
}

That “snaps” the background to full-width. If we add a little transition to this, then we see the stripes expand on hover:

section:hover > div:nth-child(2){
  background-size: 100% var(--h);
  transition: background-size 1s;
}

Here’s that final demo once again:

I only added text in there to show what it might look like to use this in a different context. If you do the same, then it’s worth making sure there’s enough contrast between the text color and the colors used in the gradient to comply with WCAG guidelines. And while we’re touching briefly on accessibility, it’s worth considering user preferences for reduced motion when it comes to the hover effect.

That’s a wrap!

Pretty neat, right? I certainly think so. What I like about this, too, is that it’s pretty maintainable and customizable. For example, we can alter the height, colors, and direction of the stripes by changing a few values. You might even variablize a few more things in there — like the colors and widths — to make it even more configurable.

I’m really interested if you would have approached this a different way. If so, please share in the comments! It’d be neat to see how many variations we can collect.


Animated Background Stripes That Transition on Hover originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

How to Make a Folder “Slit” Effect With CSS

When you put something — say a regular sheet of paper — in a manilla folder, a part of that thing might peek out of the folder a little bit. The same sort of thing with a wallet and credit cards. The cards poke out just a smidge so you can get a quick glance of which cards you’re carrying.

Credit: Stephen Phillips on Unsplash

I call this sort of thing a “slit”. A slit is where we create the illusion of an opening through which we can tease a visual element peeking out of it. And we can do that in CSS!

The crucial part of the design is the shadow, which is what gives the visual cue of there being a slit. Then there’s the cover for the slit which provides the space for the exhibited element to peek through from under.

Here’s what we’re going to make together:

Let’s begin with creating the shadow

You might be surprised that the shadow in the example is not created with an actual CSS shadow, like box-shadow or a drop-shadow() filter. Instead, the shadow is a separate element in itself, dark and blurred out. This is important in order to make the design more adaptable, both in its default and animated states.

The cover is the other element in the design. The cover is what I call the element that overlaps the shadow. Here’s a figure depicting how the shadow and cover come together.

The shadow is made from a small upright rectangle that has a gradient background. The gradient is darker in the middle. So when the element is blurred, it creates a shadow that’s darker in the middle; hence more dimensional.

Now, the left half of the recreated shadow is covered with a rectangle on top, colored exactly the same as the background of its container.

Both the cover and the shadow are then moved to the left ever so slightly so it appears to be layered

Working on the cover

For the cover to blend with the design’s background, its background color is inherited from its containing element. Alternatively, you can also try to blend the cover to its background using standards like CSS masks and blend modes, depending on your design choices and requirements.

To learn some basics on how these standards might be applied, you can refer to these articles: Sarah Drasner’s “Masking vs. Clipping: When to Use Each” provides an excellent primer on masks. I’ve also written about CSS blend modes in this article where you can brush up on the topic.

In the source code of my example, you’ll notice that I aligned and stacked the elements inside the <main> element using CSS Grid, which is a layout standard I often use in my demos. If you’re recreating a similar design, use a layout method that fits the best for your application to align the different parts of the design. In this case, I’ve set up a single-column grid on the <main> element which allows me to center align the cover, shadow, and image.

What CSS Grid also allows me to do is set all three of those divs so they are all full-width in the <main> container:

main > div {
  grid-area: 1 / 1;
}

This gets everything to stack on top of one another. Normally, we work hard to avoid covering elements with other elements in a grid. But this example relies on it. I’ve given the .slit-cover at width of 50% which naturally reveals the image underneath it. From there, I set a transform on it that moves it 50% in the negative direction, plus the small amount I shifted the shadow earlier (25px) to make sure that is revealed as well.

.slit-cover {
  width: 50%;
  transform: translatex(calc(-50% - 25px));
  /* etc. */
}

And there we have it! A pretty natural-looking slit that mimics something peeking out of a folder, wallet, or whatever.

There are more ways to do this! For one, Flexbox can get elements to line up in a row and align in the center like this. There are lots of ways to get things side-by-side. And maybe you have a way to use the box-shadow property, drop-shadow() filter, or even SVG filters to get the same sort of shadow effect that really sells the illusion.

And you can totally riff on this to get your own look and feel. For example, try swapping the position of the shadow and image. Or play with the color combinations and change the blur() filter value. The shape of the cover and the shadow can also be tweaked — I bet you can create a curved shadow instead of a straight one and share it with us in the comments!


How to Make a Folder “Slit” Effect With CSS originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

CSS Checkerboard Background… But With Rounded Corners and Hover Styles

On one hand, creating simple checkered backgrounds with CSS is easy. On the other hand, though, unless we are one of the CSS-gradient-ninjas, we are kind of stuck with basic patterns.

At least that’s what I thought while staring at the checkered background on my screen and trying to round those corners of the squares just a little…until I remembered my favorite bullet point glyph — — and figured that if only I could place it over every intersection in the pattern, I’ll surely get the design I want.

Turns out it’s possible! Here’s the proof.

Let’s start with the basic pattern:

<div></div>
div {
 background: 
  repeating-linear-gradient(
    to right, transparent, 
    transparent 50px, 
    white 50px, 
    white 55px
  ),
  repeating-linear-gradient(
    to bottom, transparent,  
    transparent 50px, 
    white 50px, 
    white 55px
  ),
  linear-gradient(45deg, pink, skyblue);
  /* more styles */
}

What that gives us is a repeating background of squares that go from pink to blue with 5px white gaps between them. Each square is fifty pixels wide and transparent. This is created using repeating-linear-gradient, which creates a linear gradient image where the gradient repeats throughout the containing area.

In other words, the first gradient in that sequence creates white horizontal stripes and the second gradient creates white vertical stripes. Layered together, they form the checkered pattern, and the third gradient fills in the rest of the space.

Now we add the star glyph I mentioned earlier, on top of the background pattern. We can do that by including it on the same background property as the gradients while using an encoded SVG for the shape:

div {
  background: 
    repeat left -17px top -22px/55px 55px
    url("data:image/svg+xml,
    <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 35px 35px'>
      <foreignObject width='35px' height='35px'>
        <div xmlns='http://www.w3.org/1999/xhtml' style='color: white; font-size: 35px'>✦</div>
      </foreignObject>
    </svg>"
    ), 
    repeating-linear-gradient(
      to right, transparent,
      transparent 50px,
      white 50px,
      white 55px
    ),
    repeating-linear-gradient(
      to bottom, transparent,
      transparent 50px,
      white 50px,
      white 55px
    ),
    linear-gradient(45deg, pink, skyblue);
  /* more style */
}

Let’s break that down. The first keyword, repeat, denotes that this is a repeating background image. Followed by that is the position and size of each repeating unit, respectively (left -17px top -22px/55px 55px). This offset position is based on the glyph and pattern’s size. You’ll see below how the glyph size is given. The offset is added to re-position the repeating glyph exactly over each intersection in the checkered pattern.

The SVG has an HTML <div> carrying the glyph. Notice that I declared a font-size on it. That ultimately determines the border radius of the squares in the checkerboard pattern — the bigger the glyph, the more rounded the squares. The unrolled SVG from the data URL looks like this:

<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 35px 35px'>
  <foreignObject width='35px' height='35px'>
    <div xmlns='http://www.w3.org/1999/xhtml' style='color:white;font-size:35px'>✦</div>
  </foreignObject>
</svg>

Now that a CSS pattern is established, let’s add a :hover effect where the glyph is removed and the white lines are made slightly translucent by using rgb() color values with alpha transparency.

div:hover {
  background:
    repeating-linear-gradient(
      to right, transparent,
      transparent 50px,
      rgb(255 255 255 / 0.5) 50px,
      rgb(255 255 255 / 0.5) 55px
    ),
    repeating-linear-gradient(
      to bottom, transparent,
      transparent 50px,
      rgb(255 255 255 / 0.5) 50px,
      rgb(255 255 255 / 0.5) 55px
    ),
  linear-gradient(45deg, pink, skyblue);
  box-shadow: 10px 10px 20px pink;
}

There we go! Now, not only do we have our rounded corners, but we also have more control control over the pattern for effects like this:

Again, this whole exercise was an attempt to get a grid of squares in a checkerboard pattern that supports rounded corners, a background gradient that serves as an overlay across the pattern, and interactive styles. I think this accomplishes the task quite well, but I’m also interested in how you might’ve approached it. Let me know in the comments!


CSS Checkerboard Background… But With Rounded Corners and Hover Styles originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Why (and How) I Write Code With Pencil and Paper

If the thought of handwriting code seems silly, it might surprise you to know that it’s inevitable. If you’re unsure, think about the last job interview you did, and remember how there was no computer around in the interview room — just your interviewers, a blank sheet of paper, and a blue ball-point pen.

For the students among you, it’s even a bigger deal as your grades hang in by the lines of code you had strategically squeezed into the available space in your answer sheet.

And not just that, experienced programmers can point you to the bundle of A4 sheets they had removed from the office copy machine to scribble down a particularly complex algorithm they had been working on.

So whether you’re an exam student, potential job interviewee, or someone wanting to resolve their programming dead ends, I hope this article helps you out when you put your pen to the paper to code.

Although I will focus on the analog aspect of writing code, you can apply these steps to coding in any form or language. So consider this to be also like a generic coding guideline that works specifically for me but can also be very useful to you in your work.

Why write it down?

Before we start, it’s essential to understand that no one expects you to jot down production-ready code in a notebook. It’s not like you can drop that into a code editor and compile it without an error. If producing perfect code was the goal, you would be seated in front of a computer in the interview rooms and exam halls.

The purpose of handwriting code is to work through logic in advance. There’s s desire to “get in the browser” as soon as possible in design, but there is conventional wisdom in sketching designs by hand. A low-fidelity medium encourages quick experimentation and inexpensive mistakes.

White lined paper with cursive handwritten notes on using :nth-child.
The toil of trying to figure out how to affect surrounding items with one click (from my last article)

The same can be true of code, mainly when working out syntax and semantics. That said, getting the correct syntax and semantics is always a plus point, though not the sole focus of the whole handwriting exercise.

Let’s see where we can start when it comes to handwriting code.

Know your question

During my final year in college, I couldn’t do an internship or even attend campus interviews because of health reasons. As a result, my very first job interview was quite literal with high stakes.

When I look back now, the interview was pretty easy. But having never attended one before, I was anxious beyond reason. The first thing the interviewers asked about programming was if I could output an inverted triangle made of asterisks. As I said, it was easy — nothing a for loop can’t handle, right? But like I said, my anxiety was through the roof as well.

I took a deep breath, pressed my palm against the blank sheet of paper they had laid out for me, slid it as slow as possible towards me on the table (buying time, of course), clicked the pen, and then I did something right.

I first drew an inverted triangle made of asterisks. That’s how I found my feet on the ground to start answering their question.

I’ve seen otherwise brilliant developers get something wrong simply because they never fully grasp what it is they are solving.

The questions we work with are not like the questions physicists or mathematicians solve. They get a set of parameters and find the missing ones; our questions are also our results. We are already told what our results are — we have to figure out how to reach them. That’s why it’s imperative to know the question well because you’ll see the result.

Writing down or drawing out what you want to output is one of the best ways to start your coding. I understand that in our fast-paced industry, the expectation is that we have to jump right into the programming by running a “hello world” demo. And that’s great to familiarize yourself with an unfamiliar syntax and shake off your anxiousness about trying something new.

But when someone asks you a question and gives you a result to work up to, wouldn’t it just be better to put that down first? That question/result is not only your starting point but also your point of reference. At any step in your coding, you can look at it to ensure you’re working towards it and that you’re on the right track.

So whether in your answer sheets or in that blank A4 paper you’re about to write in, start by taking a second and writing down what it is you’re trying to output. You can put it in the margins or a corner if you don’t want it to be a part of your answer. Just make sure it’s somewhere where you can keep referencing it.

Outline your code

This step is like a double-edged sword. It can get you a roadmap to your program or waste your time. My job is to make sure it’s the former.

So, first and foremost, I like to say: outlining code is unnecessary if the scope of your problem or question is small. Again, this practice is neither prescriptive nor universal to all projects or situations. Imagine I’m your interviewer, and I ask you to write how to center an element in a web page using CSS in as many ways as possible. You won’t exactly be needing an outline for this. The code snippets are relatively small for each method.

But now, let’s say I assign you to write a web application that captures user signatures via a touchscreen interface and then saves the signature on the server. Not so straightforward, right? You’ve more than one thing to figure out. Perhaps, a little outline can help.

  1. UI for capturing signature — HTML Canvas? WebGL?
  2. Disable pointer events on the rest of the web page when the user is signing
  3. Convert and save the captured image to a PNG file — JS
  4. Then convert it to blob (maybe) and save it to the visitor’s log data table.

I’ve written a rough sequence of actions I think I might have to code. It could’ve been shorter or longer, depending on what I wanted from it.

I highly recommend outlining code for client projects. Write the outline along with your user requirements or on the back of wireframes you’ve printed out.

Your quick snapshot of bullet points gives you a map, a to-do list, and a checklist to verify against when you reach the end of the project — pretty much your whole project’s summary in a low-fidelity list. It can also become a template to start your next similar project.

But like I said before, this step is like a double-edged sword. You’ll have to keep this short for examinees and interviewees when there are time constraints.

If you don’t know where to start, write down just three essential functions you’ll have to code in your application, and if you have got the time, make it five.

But that’s about it. Spend as little time as possible on this, and don’t sweat over the details. The outline is not going to score you extra points. It’s there only to help you make sure you have everything covered. It captures your initial gut reaction and keeps you honest throughout the project’s life.

Longhand vs. shorthand

White lined paper with cursive handwritten notes in black ink.
A quick reference to disable text selection

Time to start coding. So, what do you write? “Bdrs” or “border-radius“; “div -> p” or “<div><p></div></p>“; “pl()” or “println()“; “q()” or “querySelector()“?

If someone else is grading your code, then there’s no choice. Leave out abbreviations, pseudo-codes, Emmet shortcuts, and any other form of shorthand writing. Otherwise, there’s no reason to assume that anyone reading this knows what your abbreviations mean.

It’s really up to you.

If you’ve gotten out of touch with writing by hand — and many of us have — it’s better not to go overboard with the longhand notations, as they get tedious. At the same time, there’s no such thing as being too frugal with your writing. Not if you want to be able to look back on it one day and understand what you’d written down.

I have an open file in my note-taking app and a lined notepad on my desk where I write down code snippets I want to save for later reference. They are unorganized, just a long stream of snippets. That’s why when I browse through older notes, I wouldn’t know what I meant to write if I had not written them down clearly.

I forget syntaxes all the time. For instance, I’ve been using the arrow notation for JavaScript functions since it was introduced (because it’s shorter), and I’m pretty sure if someone suddenly asks me to define a function using the function keyword, I might even misplace the parentheses or the function name, inciting a syntax error.

It’s not unusual for us to forget syntaxes we haven’t used in a while. That’s why it’s better to write your notes clearly when you know you need them for future reference.

The non-sequential flow of code

Unlike the last step, which doesn’t apply to those of you interviewees and test-takers, this one is catered especially to you.

Most programming languages are interpreted, compiled, and executed so that sometimes pre-written code in the source is executed later when called. We do it in JavaScript, for example, with function calling — functions can be defined initially, then executed later. Examinees and interviewees can use this to start working on the critical point of your answer first.

As I’ve said from the very beginning, the purpose of handwriting code is to work through or test the logic of whatever it is you program. It’s best when you focus on resolving that first.

Let’s take a classic textbook example — a program to find the nth Fibonacci number. If I were to write a simple outline for it, it would be something like this:

  1. Get the input.
  2. Calculate the Fibonacci number.
  3. Summarise the output.
  4. Print the output.

All the steps in that outline are essential; however, 1, 3, and 4 are more obligatory. They are necessary but not important enough to focus on right away.

It’s better to start writing down the code to calculate the Fibonacci number rather than to fetch the input. Wrap it in a function, then go ahead and write the code sequentially and write down a line to call that function where appropriate.

Spend your time writing code that focuses on the heart of the problem.

Real professionals can skip ahead. Let’s say I have a client project, and I have to work with some triangle geometry — got two sides, opposite angle, and gotta find the third side’s length. And I’ve decided to scribble on paper to get started rather than opening my IDE.

First, I would draw the triangle, of course (that’s something I’m very experienced with, as you can tell). I would write down some sample lengths and angles. Then I’d write the formula (compliments of online searching, for sure), and then I’d jump right to the code for the function.

There’s no point in me writing down the obligatory steps even though I’ll need them in production-ready code. But it would be different if I had to write that on an answer sheet in an exam. I can’t skip the other steps; however, I can still start with the code for the formula.

Pseudo-code

Chris has already written a handy article on pseudo-code that I highly recommend you give a solid read.

For all those professionals who feel like the whole handwriting code thing doesn’t seem like your cup of tea but still might be curious if it can help you, then pseudo-code might be the balance you’re looking for.

It’s similar to outlining the code, as I mentioned in one of the previous steps. However, it’s briefer and feels more like shorthand coding. It’s sometimes also referred to as “skeleton code.”

Here’s some quick pseudo-code for a CSS grid layout:

Grid
5 60px rows
6 100px columns

There isn’t much to write! So, even though putting a pencil to paper is excellent for this sort of thing, it’s just as effective, fast, and inexpensive to jot some pseudo code into whatever program you’re using.

Space and comments

I believe code is 90% keywords and 10% tabs. Withoutspacesthereadabilityofwordsdecreases. Indentations are necessary for handwritten code as well. However, please don’t use it for every level because the width of the paper will limit you. Use spaces judiciously, but use them.

Yellow unlined paper with code handwritten in cursive in black ink.
Prized OG snippet, written with extra TLC

If you’re writing code for your use, I also believe that if you’ve followed everything I’ve mentioned so far and have already written down your output and an outline on the page, you may not even need to include comments. Comments tell you quickly what its following set of code does. If you have already written and read an outline for the code, then comments are redundant notes.

However, if your judgment says to put down one, then do it. Add it to the right side of the code (since you won’t be able to insert it between already written lines the way you could in, say, VS Code). Use forward slashes, brackets, or arrows to denote that they are comments.

For examinees who are unconfident with a certain syntax, write down comments. This way, at least, you’re letting the person grading your paper know your intention with that incorrectly formatted code. And use only the correct delimiters to denote comments — for example, that would be the forward slashes for JavaScript.

Analog vs. digital

As I mentioned earlier, everything I’m providing here can is generic coding advice. If you don’t want to try this with physical paper, any note-taking application also works.

But if you’re going to try the digital route, my recommendation is to try using something other than a straight note-taking app. Work with more visual digital tools — flow diagrams, mind maps, wireframes, etc. They can help you visualize your result, the outlines, and the code itself.

I am not much of a digital citizen (except for working on the web and recently converting to reading e-books), so I stick to physical notebooks.

My favorite tools for handwriting code

Any pencil and paper will do! But there are lots of options out there, and these are a few choice tools I use:

There is no “write” way to code

I hope, if nothing else, my little way of handwriting code with pencil and paper makes you evaluate the way you already plan and write code. I like knowing how other developers approach their work, and this is my way of giving you a peek into the way I do things.

Again, nothing here is scientific or an exact art. But if you want to give handwritten code planning a try, here’s everything we’ve covered in a nice ordered list:

  1. Start by writing down (with sample data, if needed) the output of your code.
  2. Write an outline for the code. Please keep it to three steps for small projects or ones that are less complex.
  3. Use longhand notations. Developers writing for themselves can use shorthand notations as long as the writing is legible and makes sense to you when you refer to it later.
  4. When under a time constraint, consider writing the code that tackles the heart of the problem first. Later, write down a call to that code at the right place in your sequential code.
  5. If you feel confident, try writing pseudo code addressing the main idea.
  6. Use proper indentations and spaces — and be mindful of the paper’s width.

That’s it! When you’re ready to try writing code by hand, I hope this article makes it easy for you to start. And if you’re sitting down for an exam or an interview, I hope this helps you focus on getting the questions right.


Why (and How) I Write Code With Pencil and Paper originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Conditionally Styling Selected Elements in a Grid Container

Calendars, shopping carts, galleries, file explorers, and online libraries are some situations where selectable items are shown in grids (i.e. square lattices). You know, even those security checks that ask you to select all images with crosswalks or whatever.

🧐

I found a neat way to display selectable options in a grid. No, not recreating that reCAPTCHA, but simply being able to select multiple items. And when two or more adjoining items are selected, we can use clever :nth-of-type combinators, pseudo elements, and the :checked pseudo-class to style them in a way where they look grouped together.

The whole idea of combinators and pseudos to get the rounded checkboxes came from a previous article I wrote. It was a simple single-column design:

This time, however, the rounding effect is applied to elements along both the vertical and horizontal axes on a grid. You don’t have to have read my last article on checkbox styling for this since I’m going to cover everything you need to know here. But if you’re interested in a slimmed down take on what we’re doing in this article, then that one is worth checking out.

Before we start…

It’ll be useful for you to take note of a few things. For example, I’m using static HTML and CSS in my demo for the sake of simplicity. Depending on your application you might have to generate the grid and the items in it dynamically. I’m leaving out practical checks for accessibility in order to focus on the effect, but you would definitely want to consider that sort of thing in a production environment.

Also, I’m using CSS Grid for the layout. I’d recommend the same but, of course, it’s only a personal preference and your mileage may vary. For me, using grid allows me to easily use sibling-selectors to target an item’s ::before and ::after pseudos.

Hence, whatever layout standard you might want to use in your application, make sure the pseudos can still be targeted in CSS and ensure the layout stays in tact across different browsers and screens.

Let’s get started now

As you may have noticed in the earlier demo, checking and unchecking a checkbox element modifies the design of the boxes, depending on the selection state of the other checkboxes around it. This is possible because I styled each box using the pseudo-elements of its adjacent elements instead of its own element.

The following figure shows how the ::before pseudo-elements of boxes in each column (except the first column) overlap the boxes to their left, and how the ::after pseudo-elements of boxes in each row (except the first row) overlap the boxes above.

Two grids of checkboxes showing the placement of before and after pseudos.

Here’s the base code

The markup is pretty straightforward:

<main>
  <input type=checkbox> 
  <input type=checkbox> 
  <input type=checkbox>
  <!-- more boxes -->
</main>

There’s a little more going on in the initial CSS. But, first, the grid itself:

/* The grid */
main {
  display: grid;
  grid:  repeat(5, 60px) / repeat(4, 85px);
  align-items: center;
  justify-items: center;
  margin: 0;
}

That’s a grid of five rows and four columns that contain checkboxes. I decided to wipe out the default appearance of the checkboxes, then give them my own light gray background and super rounded borders:

/* all checkboxes */
input {
  -webkit-appearance: none;
  appearance: none;
  background: #ddd;
  border-radius: 20px;
  cursor: pointer;
  display: grid;
  height: 40px;
  width: 60px;
  margin: 0;
}

Notice, too, that the checkboxes themselves are grids. That’s key for placing their ::before and ::after pseudo-elements. Speaking of which, let’s do that now:

/* pseudo-elements except for the first column and first row */
input:not(:nth-of-type(4n+1))::before,
input:nth-of-type(n+5)::after {
  content: '';        
  border-radius: 20px;
  grid-area: 1 / 1;
  pointer-events: none;
}

We’re only selecting the pseudo-elements of checkboxes that are not in the first column or the first row of the grid. input:not(:nth-of-type(4n+1)) starts at the first checkbox, then selects the ::before of every fourth item from there. But notice we’re saying :not(), so really what we’re doing is skipping the ::before pseudo-element of every fourth checkbox, starting at the first. Then we’re applying styles to the ::after pseudo of every checkbox from the fifth one.

Now we can style both the ::before and ::after pseudos for each checkbox that is not in the first column or row of the grid, so that they are moved left or up, respectively, hiding them by default.

/* pseudo-elements other than the first column */
input:not(:nth-of-type(4n+1))::before { 
  transform: translatex(-85px);
}

/* pseudo-elements other than the first row */
input:nth-of-type(n+5)::after {
 transform: translatey(-60px); 
}

Styling the :checked state

Now comes styling the checkboxes when they are in a :checked state. First, let’s give them a color, say a limegreen background:

input:checked { background: limegreen; }

A checked box should be able to re-style all of its adjacent checked boxes. In other words, if we select the eleventh checkbox in the grid, we should also be able to style the boxes surrounding it at the top, bottom, left, and right.

A four-by-five grid of squares numbered one through 20. 11 is selected and 7, 10, 12, and 15 are highlighted.

This is done by targeting the correct pseudo-elements. How do we do that? Well, it depends on the actual number of columns in the grid. Here’s the CSS if two adjacent boxes are checked in a 5⨉4 grid:

/* a checked box's right borders (if the element to its right is checked) */
input:not(:nth-of-type(4n)):checked + input:checked::before { 
  border-top-right-radius: 0; 
  border-bottom-right-radius: 0; 
  background: limegreen;
}
/* a checked box's bottom borders (if the element below is checked) */
input:nth-last-of-type(n+5):checked + * + * + * + input:checked::after {
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
  background: limegreen;
}
/* a checked box's adjacent (right side) checked box's left borders */
input:not(:nth-of-type(4n)):checked + input:checked + input::before {         
  border-top-left-radius: 0; 
  border-bottom-left-radius: 0; 
  background: limegreen;
}
/* a checked box's adjacent (below) checked box's top borders */
input:not(:nth-of-type(4n)):checked + * + * + * +  input:checked + input::before { 
  border-top-left-radius: 0; 
  border-top-right-radius: 0; 
  background: limegreen;
}

If you prefer you can generate the above code dynamically. However, a typical grid, say an image gallery, the number of columns will be small and likely a fixed number of items, whereas the rows might keep increasing. Especially if designed for mobile screens. That’s why this approach is still an efficient way to go. If for some reason your application happens to have limited rows and expanding columns, then consider rotating the grid sideways because, with a stream of items, CSS Grid arranges them left-to-right and top-to-bottom (i.e. row by row).

We also need to add styling for the last checkboxes in the grid — they’re not all covered by pseudo-elements as they are the last items in each axis.

/* a checked box's (in last column) left borders */
input:nth-of-type(4n-1):checked + input:checked {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}
/* a checked box's (in last column) adjacent (below) checked box's top borders */
input:nth-of-type(4n):checked + * + * + * + input:checked {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

Those are some tricky selectors! The first one…

input:nth-of-type(4n-1):checked + input:checked

…is basically saying this:

A checked <input> element next to a checked <input> in the second last column.

And the nth-of-type is calculated like this:

4(0) - 1 = no match
4(1) - 1 = 3rd item
4(2) - 1 = 7th item
4(3) - 1 = 11th item
etc.

So, we’re starting at the third checkbox and selecting every fourth one from there. And if a checkbox in that sequence is checked, then we style the checkboxes adjacent, too, if they are also checked.

And this line:

input:nth-of-type(4n):checked + * + * + * + input:checked

Is saying this:

An <input> element provided that is checked, is directly adjacent to an element, which is directly adjacent to another element, which is also directly adjacent to another element, which, in turn, is directly adjacent to an <input> element that is in a checked state.

What that means is we’re selecting every fourth checkbox that is checked. And if a checkbox in that sequence is checked, then we style the next fourth checkbox from that checkbox if it, too, is checked.

Putting it to use

What we just looked at is the general principle and logic behind the design. Again, how useful it is in your application will depend on the grid design.

I used rounded borders, but you can try other shapes or even experiment with background effects (Temani has you covered for ideas). Now that you know how the formula works, the rest is totally up to your imagination.

Here’s an instance of how it might look in a simple calendar:

Again, this is merely a rough prototype using static markup. And, there would be lots and lots of accessibility considerations to consider in a calendar feature.


That’s a wrap! Pretty neat, right? I mean, there’s nothing exactly “new” about what’s happening. But it’s a good example of selecting things in CSS. If we have a handle on more advanced selecting techniques that use combinators and pseudos, then our styling powers can reach far beyond the styling one item — as we saw, we can conditionally style items based on the state of another element.


Conditionally Styling Selected Elements in a Grid Container originally published on CSS-Tricks. You should get the newsletter.

How to Create CSS Charts With Interesting Shapes, Glyphs and Emoji

Let’s forego the usual circles and bars we typically see used in charts for more eccentric shapes. With online presentations more and more common today, a quick way to spruce up your web slides and make them stand out is to give the charts a shapely makeover 🪄

I’ll show you how to create charts with interesting shapes using glyphs, CSS shapes, and emojis with minimal effort.

Let’s start with a simple example.

Using glyphs

<div id="chart">
  <div id="chart-shape">⬠</div>
  <div id="chart-value"></div> 
</div>
#chart {
  width: 300px; 
  height: 300px;
  display: grid;
  background: white;
}
#chart * {
  height: inherit;
  grid-area: 1 / 1;
}

We first give the chart some dimensions and stack the two div inside it by assigning them to the same grid cell. They can be stacked up using any other way, too — with position property, for instance.

Look at the HTML above one more time. One of the divs has a pentagon symbol — the chart shape we want. I added that symbol using the “Emoji and Symbols” keyboard, though it can also be done with the HTML entity value for pentagon, &#x2B20;, inside the div.

The div with the symbol is then styled with CSS font properties as well as a desired chart color. It’s large enough and centered.

#chart-shape {
  font: 300px/300px serif;
  text-align: center; 
  color: limegreen;
}

To the second div in the HTML contains a conic gradient background image. The percentage of the gradient represents the visual value of the chart. The same div also has mix-blend-mode: screen;.

#chart-value {
  background: conic-gradient(transparent 75%, darkseagreen 75%);
  mix-blend-mode: screen;
}

The mix-blend-mode property blends colors inside an element with its backdrop. The screen blend mode value causes a lighter blend to come through. A lighter green shows through the portion where the darkseagreen colored part of the conic gradient overlaps with the limegreen colored pentagram, while the rest of the darskseagreen gradient disappears against the white backdrop of the chart.

An alternative to adding the chart shape in the HTML is to add it as another background layer in CSS and use background-blend-mode instead of mix-blend-mode. However, the code for a chart shape inside the CSS can be less legible for a quick glance. So it’s up to you to see where it’ll be easier for you to add the chart shape in: HTML or CSS. You’ve both options.

#chart {
  width: 300px; 
  height: 300px;
  background:
  url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><foreignObject width='300px' height='100%'><div xmlns='http://www.w3.org/1999/xhtml' style='font:300px/300px serif;color:limegreen;text-align: center;background:white'>⬠</div></foreignObject></svg>"),
  conic-gradient(transparent 75%, darkseagreen 75%);
  background-blend-mode: screen;
}

The pentagon symbol is added as a background image in addition to the conic gradient. Then, finally, the property-value pair background-blend-mode: screen; kicks in and the result looks same as the previous demo.

The pentagon background image is created by embedding the HTML with the pentagon symbol () into an SVG that is embedded into a data URL.

<!-- Unwrapped SVG code from the Data URL -->
<svg xmlns='http://www.w3.org/2000/svg'>
  <foreignObject width='300px' height='100%'>
    <div xmlns='http://www.w3.org/1999/xhtml' 
         style='
          font:300px/300px serif;
          color:limegreen;
          text-align: center;
          background:white;'>
          ⬠
    </div>
  </foreignObject>
</svg>

Which becomes this in CSS:

background: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><foreignObject width='300px' height='100%'><div xmlns='http://www.w3.org/1999/xhtml' style='font:300px/300px serif;color:limegreen;text-align: center;background:white'>⬠</div></foreignObject></svg>");

Using CSS shapes

Next, let’s use CSS shapes in place of symbols. CSS shapes are primarily created with the use of border properties. We have a collection of CSS shapes in our archive for your reference.

Here’s a set of properties that can create a simple triangle shape in an element we’ll later add to the SVG, replacing the symbol:

border: 150px solid white; 
border-bottom: 300px solid lime; 
border-top: unset;

When combined with the conic gradient and the background blend, the result is:

<div id="chart"></div>
#chart {
  width: 300px;
  height: 300px;
  background:
  url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><foreignObject width='300px' height='100%'><html xmlns='http://www.w3.org/1999/xhtml'><div style='border:150px solid white; border-bottom:300px solid lime; border-top:unset'></div><div style='border:150px solid transparent; border-bottom:300px solid white; border-top:unset; transform:scale(0.8) translateY(-360px);'></div></html></foreignObject></svg>"),
  conic-gradient(transparent 75%, darkseagreen 75%);
  background-blend-mode: screen;
}

To restrict the design to the border, a smaller white triangle was added to the design.

<!-- Unwrapped SVG code from the Data URL -->
<svg xmlns='http://www.w3.org/2000/svg'>
  <foreignObject width='300px' height='100%'>
   <html xmlns='http://www.w3.org/1999/xhtml'>
    /* green triangle */
    <div style='
         border: 150px solid white; 
         border-bottom: 300px solid lime; 
         border-top: unset'></div>
    /* smaller white triangle */
    <div style='
         border: 150px solid transparent; 
         border-bottom: 300px solid white; 
         border-top: unset; 
         transform: scale(0.8) translateY(-360px);'></div>
   </html>
  </foreignObject>
</svg>

Which, again, becomes this in CSS:

background: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><foreignObject width='300px' height='100%'><html xmlns='http://www.w3.org/1999/xhtml'><div style='border:150px solid white; border-bottom:300px solid lime; border-top:unset'></div><div style='border:150px solid transparent; border-bottom:300px solid white; border-top:unset; transform:scale(0.8) translateY(-360px);'></div></html></foreignObject></svg>");

Using emojis

Will emojis work with this approach to charts? You bet it will! 🥳

A block-colored emoji is fed into the SVG image the same way the HTML symbols are. The block color of the emoji is created by giving it a transparent color value, followed by adding a desired color as text-shadow. I covered this technique in another post.

<div id="chart"></div>
#chart {
  width: 300px; 
  height: 300px;
  background: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><foreignObject width='300px' height='300px'><body style='margin:0;text-align:center;color:transparent;' xmlns='http://www.w3.org/1999/xhtml'><div style='text-shadow: 0 0 limegreen;font:200px/300px serif;background:white;'>🍏</div><div style='text-shadow:0 0 white;font:170px/300px serif;position:relative;top:-300px;'>🍏</div></body></foreignObject></svg>"),
  conic-gradient(transparent 64%, darkseagreen 64%);
  background-blend-mode: screen;
}

Just as with the last demo, a smaller white apple shape is added at the center to create the border design.

<!-- Unwrapped SVG code from the Data URL -->
<svg xmlns='http://www.w3.org/2000/svg'>
  <foreignObject width='300px' height='300px'>
    <body xmlns='http://www.w3.org/1999/xhtml' style='
          margin: 0;
          text-align: center;
          color:transparent;'>
       /* green apple shape */
       <div style='
            text-shadow: 0 0 limegreen; 
            font-size: 200px; 
            background: white;'>🍏</div>
       /* smaller white apple shape */
       <div style='
            text-shadow:0 0 white; 
            font-size: 170px; 
            position: relative; 
            top: -300px;'>🍏</div>
    </body>
  </foreignObject>
</svg>

I added the two divs inside the <body> element so the repeating style properties of the divs are declared only once in the body element. The divs will then automatically inherit those properties.

Chris had the idea to animate the conic gradient — its percent value to be specific — using the CSS @property (supported in Chrome at the time of writing this article), and it just has the most beautiful effect on the design. @property is a CSS at-rule that explicitly defines a custom CSS property. In supported browsers, when a custom property is defined using @property it can be animated.

@property --n {
  syntax: '<percentage>';
  inherits: true;
  initial-value: 30%;
}
#chart {
  width: 300px; 
  height: 300px;
  --n: 30%;  /*declaration for browsers with no @property support */
  background: 
    url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><foreignObject width='300px' height='300px'><body style='margin:0;text-align:center;color:transparent;' xmlns='http://www.w3.org/1999/xhtml'><div style='text-shadow: 0 0 limegreen;font:200px/300px serif;background:white;'>🍏</div><div style='text-shadow:0 0 white;font:170px/300px serif;position:relative;top:-300px;'>🍏</div></body></foreignObject></svg>"),
    conic-gradient(transparent var(--n), darkseagreen var(--n));
  background-blend-mode: screen;
  transition: --n 2s ease-in-out	
}
#chart:hover { --n: 70%; }

The chart above will change its value on hover. In Chrome, the change will look animated.

And although it won’t be as smooth as CSS animation, you can also try animating the gradient using JavaScript. The following JavaScript will cause a somewhat similar animating effect as the above when the cursor moves over the chart.

const chart = document.querySelector('#chart')
chart.onpointerover = ()=>{
  var i = 30,
      timer = setInterval(()=> {
        if (i < 70)
          chart.style.setProperty('--n', i++ + '%')
        else clearInterval(timer)
      }, 10)
}
chart.onpointerout = ()=>{
  var i = 70,
      timer = setInterval(()=> {
        if (i >= 30) 
          chart.style.setProperty('--n', i-- + '%')
        else clearInterval(timer)
      }, 10)
}

When trying your own designs, keep in mind how the different blend modes work. I used the screen blend mode in all my demos just to keep things simple. But with different blend modes, and different backdrop colors, you’ll get varying results. So, I recommend going deeper into blend modes if you haven’t already.

Also, if you want to exclude an element’s color from the final result, try isolation: isolate; on the element — the browser will ignore that backdrop color when applying the blend.

And even though there are all kinds of unusual and quirky shapes we can use in any wild colors we want, always be mindful of the legibility by making the chart value large and clear enough to read.


The post How to Create CSS Charts With Interesting Shapes, Glyphs and Emoji appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

How to Create Actions for Selected Text With the Selection API

Click, drag, release: you’ve just selected some text on a webpage — probably to copy and paste it somewhere or to share it. Wouldn’t it be cool if selecting that text revealed some options that make those tasks easier? That’s what a selection menu does.

You may already be familiar with selection menus if you’ve ever used an online editor. When you select text, options to format the selection might float above it. In fact, I’m writing this draft in an editor that does exactly this.

Let’s see how we can create a selection menu like this using JavaScript’s Selection API. The API gives us access to the space and content of the selected area on a webpage. This way we can place the selection menu exactly above the selected text and get access to the selected text itself.

Here’s an HTML snippet with some sample text:

<article>
  <h1>Select over the text below</h1> 
  <p>Cascading Style Sheets (CSS) is a style sheet language used for describing the presentation of a document written in a markup language such as HTML. CSS is a cornerstone technology of the World Wide Web, alongside HTML and JavaScript. CSS is designed to enable the separation of presentation and content, including layout, colors, and fonts. This separation can improve content accessibility, provide more flexibility and control in the specification of presentation characteristics. </p>
</article>
<template><span id="control"></span></template>

There’s a <template> tag at the end there. The <span> inside it is our selection menu control. Anything inside a <template> tag is not rendered on the page until it’s later added to the page with JavaScript. We’ll add the selection menu control to the page when user selects text. And when the user selects that text, our selection menu will prompt the user to tweet it.

Here’s the CSS to style it:

#control {
    background-image: url("data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 width='40px' height='40px'><foreignObject width='40px' height='40px'><div xmlns='http://www.w3.org/1999/xhtml' style='width:40px;height:40px;line-height:40px;text-align:center;color:transparent;text-shadow: 0 0 yellow, 2px 4px black, -1px -1px black;font-size:35px;'>💬</div></foreignObject></svg>");
  cursor: pointer;
  position: absolute;
  width: 40px;
  height: 40px;
}
#control::before{
  background-color: black;
  color: white;
  content: " tweet this! ";
  display: block;
  font-weight: bold;
  margin-left: 37px;
  margin-top: 6px;
  padding: 2px;
  width: max-content;
  height: 20px;
}

Check out this article to learn how I used an emoji (💬) for the background image.

So far, the sample text is ready, and the selection menu control has been styled. Let’s move on to the JavaScript. When a selection is made, we’ll get the size and position of the selected area on the page. We then use those measurements to assign the position of the selection menu control at the top-middle of the selected area.

var control = document.importNode(document.querySelector('template').content, true).childNodes[0];
document.querySelector('p').onpointerup = () => {
  let selection = document.getSelection(), text = selection.toString();
  if (text !== "") {
    let rect = selection.getRangeAt(0).getBoundingClientRect();
    control.style.top = `calc(${rect.top}px - 48px)`;
    control.style.left = `calc(${rect.left}px + calc(${rect.width}px / 2) - 40px)`;
    control['text']= text; 
    document.body.appendChild(control);
  }
}

In this code, we first get a copy of the selection menu control inside <template>, then assign it to the control variable.

Next, we write the handler function for the onpointerup event of the element carrying the sample text. Inside the function, we get the selection and the selected string using document.getSelection(). If the selected string is not empty, then we get the selected area’s size and position, via getBoundingClientRect(), and place it in the rect variable.

Using rect, we calculate and assign the top and left positions of the control. This way, the selection menu control is placed a little above the selected area and centered horizontally. We’re also assigning the selected string to a user-defined property of control. This will later be used to share the text.

And, finally, we add control to the webpage using appendChild(). At this point, if we select some of the sample text on the page, the selection menu control will appear on the screen.

Now we get to code what happens when the selection menu control is clicked. In other words, we’re going to make it so that the text is tweeted when the prompt is clicked.

control.addEventListener('pointerdown', oncontroldown, true);

function oncontroldown(event) {
  window.open(`https://twitter.com/intent/tweet?text=${this.text}`)
  this.remove();
  document.getSelection().removeAllRanges();
  event.stopPropagation();
}

When the control is clicked, a tab opens with Twitter’s “New Tweet” page, complete with the selected text ready to go.

After the tweet prompt, the selection menu control is no longer needed and is removed, along with any selection made on the page. The way that the pointerdown event cascades further down the DOM tree is also stopped at this point.

We also need an event handler for the onpointerdown event of the page:

document.onpointerdown = ()=> {    
  let control = document.querySelector('#control');
  if (control !== null) {control.remove();document.getSelection().removeAllRanges();}
}

Now the control and any selection made on the page are removed when clicking anywhere on the page but the selection menu control.

Demo

Here’s a more prettified version that Chris put together:

And here’s an example showing more than one control in the selection menu:

About that <template>

It’s not totally necessary that we use it. Instead, you can also try simply hiding and showing the control some other way, like the hidden HTML attribute or the CSS display. You can also build a selection menu control in the JavaScript itself. The coding choices will depend on how efficiently you execute them, and their fallbacks, if needed, as well as how they fit in with your application.

Some UI/UX advice

While this is a nice effect, there are a couple of things to consider when using it to ensure a good user experience. For example, avoid injecting your own text into the text selection — you know, like appending a link back to your site in the auto-generated tweet. It’s intrusive and annoying. If there’s any reason to do that, like adding the source citation, let the user see a preview of the final text before posting it. Otherwise, the user might be confused or surprised by the addition.

One more thing: It’s best if the menu control is out of the way. We don’t want it covering up too much of the surrounding content. That sort of thing adds up to CSS “data loss” and we want to avoid that.

Bottom line: Understand why your users need to select text on your website and add the controls in a way that gets out of the way of what they’re trying to do.


The post How to Create Actions for Selected Text With the Selection API appeared first on CSS-Tricks.

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

How to Add Text in Borders Using Basic HTML Elements

Some HTML elements come with preset designs, like the inconveniently small squares of <input type="checkbox"> elements, the limited-color bars of <meter> elements, and the “something about them bothers me” arrows of the <details> elements. We can style them to match the modern aesthetics of our websites while making use of their functionalities. There are also many elements that rarely get used as both their default appearance and functionality are less needed in modern web designs.

One such HTML element is <fieldset>, along with its child element <legend>.

A <fieldset> element is traditionally used to group and access form controls. We can visually notice the grouping by the presence of a border around the grouped content on the screen. The caption for this group is given inside the <legend> element that’s added as the first child of the <fieldset>.

This combination of <fieldset> and <legend> creates a unique ready-made “text in border” design where the caption is placed right where the border is and the line of the border doesn’t go through the text. The border line “breaks” when it encounters the beginning of the caption text and resumes after the text ends.

In this post, we’ll make use of the <fieldset> and <legend> combo to create a more modern border text design that’s quick and easy to code and update.

For the four borders, we need four <fieldset> elements, each containing a <legend> element inside. We add the text that will appear at the borders inside the <legend> elements.

<fieldset><legend>Wash Your Hands</legend></fieldset>
<fieldset><legend>Stay Apart</legend></fieldset>
<fieldset><legend>Wear A Mask</legend></fieldset>
<fieldset><legend>Stay Home</legend></fieldset>

To begin, we stack the <fieldset> elements on top of each other in a grid cell and give them borders. You can stack them using any way you want — it doesn’t necessarily have to be a grid.

Only the top border of each <fieldset> element is kept visible while the remaining edges are transparent since the text of the <legend> element appears at the top border of the <fieldset> by default.

Also, we give all the <fieldset> elements a box-sizing property with a value of border-box so the width and height of the <fieldset> elements include their border and padding sizes too. Doing this later creates a leveled design, when we style the <legend> elements.

body {
  display: grid; 
  margin: auto; /* to center */
  margin-top: calc(50vh - 170px); /* to center */
  width: 300px; height: 300px; 
}

fieldset {
  border: 10px solid transparent; 
  border-top-color: black; 
  box-sizing: border-box; 
  grid-area: 1 / 1; /* first row, first column */
  padding: 20px; 
  width: inherit; 
}

After this, we rotate the last three <fieldset> elements in order to use their top borders as the side and bottom borders of our design.

/* rotate to right */
fieldset:nth-of-type(2){ transform: rotate(90deg); }
/* rotate to bottom */
fieldset:nth-of-type(3){ transform: rotate(180deg); }
/* rotate to left */
fieldset:nth-of-type(4){ transform: rotate(-90deg); }

Next up is styling the <legend> elements. The key to create smooth border text using a <legend> element is to give it a zero (or small enough) line-height. If it has a large line height, that will displace the position of the border it’s in, pushing the border down. And when the border moves with the line height, we won’t be able to connect all the four sides of our design and will need to readjust the borders.

legend {
  font: 15pt/0 'Averia Serif Libre'; 
  margin: auto; /* to center */
  padding: 0 4px; 
}

fieldset:nth-of-type(3) > legend { 
  transform: rotate(180deg);
}

I used the font shorthand property to give the values for the font-size, line-height and font-family properties of the <legend> elements.

The <legend> element that adds the text at the bottom border of our design, fieldset:nth-of-type(3)>legend, is upside-down because of its rotated <fieldset> parent element. Flip that <legend> element vertically to show its text right-side-up.

Add an image to the first <fieldset> element and you get something like this:

Lateral margins can move the text along the border. Left and right margins with auto values will center the text, as seen in the above Pen. Only the left margin with an auto value will flush the text to the right, and vice versa, for the right margin.

Bonus: After a brief geometrical detour, here’s an octagonal design I made using the same technique:


The post How to Add Text in Borders Using Basic HTML Elements appeared first on CSS-Tricks.

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

Creating CSS Shapes with Emoji

CSS Shapes is a standard that lets us create geometric shapes over floated elements that cause the inline contents — usually text — around those elements to wrap along the specified shapes.

Such a shaped flow of text looks good in editorial designs or designs that work with text-heavy contents to add some visual relief from the chunks of text.

Here’s an example of CSS Shape in use:

The shape-outside property specifies the shape of a float area using either one of the basic shape functions — circle(), ellipse(), polygon() or inset() — or an image, like this:

Inline content wraps along the right side of a left-floated element, and the left side of a right-floated element.

In this post, we’ll use the concept of CSS Shapes with emoji to create interesting text-wrapping effects. Images are rectangles. Many of the shapes we draw in CSS are also boxy or at least limited to standard shapes. Emoji, on the other hand, offers neat opportunities to break out of the box!

Here’s how we’ll do it: We’ll first create an image out of an emoji, and then float it and apply a CSS Shape to it.

I’ve already covered multiple ways to convert emojis to images in this post on creative background patterns. In that I said I wasn’t able to figure out how to use SVG <text> to do the conversion, but I’ve figured it out now and will show you how in this post.  You don’t need to have read that article for this one to make sense, but it’s there if you want to see it.

Let’s make an emoji image

The three steps we’re using to create an emoji image are:

  • Create an emoji-shaped cutout in SVG
  • Convert the SVG code to a DataURL by URL encoding and prefixing it with data:image/svg+xml
  • Use the DataURL as the url() value of an element’s background-image.

Here’s the SVG code that creates the emoji shaped cutout:

<svg width='150px' height='150px' xmlns='http://www.w3.org/2000/svg'> 
  <clipPath id='emojiClipPath'> 
    <text x='0' y='130px' font-size='130px'>🦕</text> 
  </clipPath> 
  <text x='0' y='130px' font-size='130px' clip-path='url(#emojiClipPath)'>🦕</text>
</svg>

What’s happening here is we’re providing a <text> element with an emoji character for a <clipPath>. A clip path is an outline of a region to be kept visible when that clip path is applied to an element. In our code, that outline is the shape of the emoji character.

Then the emoji’s clip path is referenced by a <text> element carrying the same emoji character, using its clip-path property, creating a cutout in the shape of the emoji.

Now, we convert the SVG code to a DataURL. You can URL encode it by hand or use online tools (like this one!) that can do it for you.

Here’s the resulted DataURL, used as the url() value for the background image of an .emoji element in CSS:

.emoji {
  background: url("data:image/svg+xml,<svg width='150px' height='150px' xmlns='http://www.w3.org/2000/svg'> <clipPath id='emojiClipPath'> <text x='0' y='130px'  font-size='130px'>🦕</text> </clipPath> <text x='0' y='130px' font-size='130px' clip-path='url(%23emojiClipPath)'>🦕</text></svg>");
}

If we were to stop here and give the .emoji element dimensions, we’d see our character displayed as a background image:

Now let’s turn this into a CSS Shape

We can do this in two steps:

  • Float the element with the emoji background
  • Use the DataURL as the url() value for the element’s shape-outside property
.emoji {
  --image-url: url("data:image/svg+xml,<svg width='150px' height='150px' xmlns='http://www.w3.org/2000/svg'> <clipPath id='emojiClipPath'> <text x='0' y='130px'  font-size='130px'>🦕</text> </clipPath> <text x='0' y='130px'  font-size='130px' clip-path='url(#emojiClipPath)'>🦕</text></svg>");
  background: var(--image-url);
  float: left;
  height: 150px;
  shape-outside: var(--image-url);
  width: 150px;
  margin-left: -6px; 
}

We placed the DataURL in a custom property, --image-url, so we can easily refer it in both the background and the shape-outside properties without repeating that big ol’ string of encoded SVG multiple times.

Now, any inline content near the floated .emoji element will flow in the shape of the emoji. We can adjust things even further with margin or shape-margin to add space around the shape.

If you want a color-blocked emoji shape, you can do that by applying the clip path to a <rect> element in the SVG:

<svg width='150px' height='150px' xmlns='http://www.w3.org/2000/svg'> 
    <clipPath id='emojiClipPath'> 
        <text x='0' y='130px' font-size='130px'>🦕</text> 
    </clipPath> 
    <rect x='0' y='0' fill='green' width='150px' height='150px' clip-path='url(#emojiClipPath)'/> 
</svg>

The same technique will work with letters!

Just note that Firefox doesn’t always render the emoji shape. We can work around that by updating the SVG code.

<svg xmlns='http://www.w3.org/2000/svg' width='150px' height='150px'>
  <foreignObject width='150px' height='150px'>
    <div xmlns='http://www.w3.org/1999/xhtml' style='width:150px;height:150px;line-height:150px;text-align:center;color:transparent;text-shadow: 0 0 black;font-size:130px;'>🧗</div>
  </foreignObject>
</svg>

This creates a block-colored emoji shape by making the emoji transparent and giving it text-shadow with inline CSS. The <div> containing the emoji and inline CSS style is then inserted into a <foreignObject> element of SVG so the HTML <div> code can be used inside the SVG namespace. The rest of the code in this technique is same as the last one.

Now we need to center the shape

Since CSS Shapes can only be applied to floated elements, the text flows either to the right or left of the element depending on which side it’s floated. To center the element and the shape, we’ll do the following:

  • Split the emoji in half
  • Float the left-half of the emoji to the right, and the right-half to the left
  • Put both sides together!

One caveat to this strategy: if you’re using running sentences in the design, you’ll need to manually align the letters on both sides.

Here’s what we’re aiming to make:

First, we see the HTML for the left and right sides of the design. They are identical.

<div id="design">
  <p id="leftSide">A C G T A <!-- more characters --> C G T A C G T A C G T <span class="emoji"></span>A C G <!-- more characters --> C G T </p>
  <p id="rightSide">A C G T A <!-- more characters --> C G T A C G T A C G T <span class="emoji"></span>A C G <!-- more characters --> C G T </p>
</div>

p#leftSide and p#rightSide inside #design are arranged side-by-side in a grid.

#design {
  border-radius: 50%; /* A circle */
  box-shadow: 6px 6px 20px silver;
  display: grid; 
  grid: "1fr 1fr"; /* A grid with two columns */
  overflow: hidden;
  width: 400px; height: 400px;
}

Here’s the CSS for the emoji:

span.emoji {
  filter: drop-shadow(15px 15px 5px green);
  shape-margin: 10px;
  width: 75px; 
  height: 150px;
}

/* Left half of the emoji */
p#leftSide>span.emoji {
  --image-url:url("data:image/svg+xml,<svg width='150px' height='150px' xmlns='http://www.w3.org/2000/svg'> <clipPath id='emojiClipPath'> <text x='0' y='130px'  font-size='130px'>🦎</text> </clipPath> <rect x='0' y='0' width='150px' height='150px' clip-path='url(%23emojiClipPath)'/></svg>");
  background-image: var(--image-url);
  float: right;
  shape-outside: var(--image-url);
}

/* Right half of the emoji */
p#rightSide>span.emoji {
  --image-url:url("data:image/svg+xml,<svg width='150px' height='150px' xmlns='http://www.w3.org/2000/svg'> <clipPath id='emojiClipPath'> <text x='-75px' y='130px'  font-size='130px'>🦎</text> </clipPath> <rect x='0' y='0' width='150px' height='150px' clip-path='url(%23emojiClipPath)'/></svg>");
  background-image: var(--image-url);
  float: left;
  shape-outside: var(--image-url);
}

The width of the <span> elements that hold the emoji images (span.emoji) is 75px whereas the width of the SVG emoji images is 150px. This automatically crops the image in half when displayed inside the spans.

On the right side of the design, with the left-floated emoji (p#rightSide>span.emoji), we need to move the emoji halfway to the left to show the right-half, so the x value in the <text> in the DataURL is changed to 75px. That’s the only difference in the DataURLs from the left and right sides of the design.

Here’s that result once again:


That’s it! You can try the above method to center any CSS Shape as long as you can split the element up into two and put the halves back together with CSS.


The post Creating CSS Shapes with Emoji appeared first on CSS-Tricks.

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

Creative Background Patterns Using Gradients, CSS Shapes, and Even Emojis

You can create stripes in CSS. That’s all I thought about in terms of CSS background patterns for a long time. There’s nothing wrong with stripes; stripes are cool. They can be customized into wide and narrow bands, criss-crossed into a checked pattern, and played with in other ways using the idea of hard stops. But stripes can be boring, too. Too conventional, out of fashion, and sometimes even unpleasant.

Thankfully, we can conjure up far more background patterns than you can even imagine with CSS, with code that is similar in spirit to stripes.

Background patterns are images repeated across a background. They can be done by referencing an external image, like a PNG file, or can be drawn with CSS, which is traditionally done using CSS gradients. 

Linear gradients (and repeating linear gradients) for instance, are typically used for stripes. But there are other ways to create cool background patterns. Let’s see how we can use gradients in other ways and toss in other things, like CSS shapes and emoji, to spice things up.

Gradient patterns

There are three types of CSS gradients.

Linear (left), radial (center) and conic (right) gradients
  1. linear-gradient(): Colors flow from left-to-right, top-to-bottom, or at any angle you choose in a single direction.
  2. radial-gradient(): Colors start at a single point and emanate outward
  3. conic-gradient(): Similar in concept to radial gradients, but the color stops are placed around the circle rather than emanating from the center point.

I recommend checking out the syntax for all the gradients to thoroughly understand how to start and end a color in a gradient.

Radial gradient patterns

Let’s look at radial gradients first because they give us very useful things: circles and ellipses. Both can be used for patterns that are very interesting and might unlock some ideas for you!

background: radial-gradient(<gradient values>)

Here’s a pattern of repeating watermelons using this technique:

background: 
	radial-gradient(circle at 25px 9px, black 2px, transparent 2px), 
	radial-gradient(circle at 49px 28px, black 2px, transparent 2px), 
	radial-gradient(circle at 38px 1px, black 2px, transparent 2px), 
	radial-gradient(circle at 20px 4px, black 2px, transparent 2px), 
	radial-gradient(circle at 80px 4px, black 2px, transparent 2px), 
	radial-gradient(circle at 50px 10px, black 2px, transparent 2px), 
	radial-gradient(circle at 60px 16px, black 2px, transparent 2px), 
	radial-gradient(circle at 70px 16px, black 2px, transparent 2px), 
	radial-gradient(ellipse at 50px 0, red 33px, lime 33px, lime 38px, transparent 38px) 
	white;
background-size: 100px 50px;

We start by providing a background size on the element then stack up the gradients inside it. An ellipse forms the green and red parts. Black circles are scattered across to represent the watermelon seeds. 

The first two parameters for a radial gradient function determine whether the gradient shape is a circle or an ellipse and the starting position of the gradient. That’s followed by the gradient color values along with the start and ending positions within the gradient.

Conic gradient patterns

Conic gradients create ray-like shapes. Like linear and radial gradients, conic gradients can be used to create geometric patterns.

background: conic-gradient(<gradient values>)
background: 
  conic-gradient(yellow 40deg, blue 40deg, blue 45deg, transparent 45deg), 
  conic-gradient(transparent 135deg, blue 135deg, blue 140deg, transparent 140deg) ;
background-size: 60px 60px;
background-color: white;

The rub with conic gradient is that it’s not supported in Firefox, at least at the time of writing. It’s always worth keeping an eye out for deeper 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.

Desktop

ChromeFirefoxIEEdgeSafari
69NoNo7912.1

Mobile / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
81No8112.2-12.4

Emoji icon patterns

This is where things begin to get interesting. Rather than just using geometric patterns (as in gradients), we now use the organic shapes of emojis to create background patterns. 🎉 

It starts with emoji icons. 

Solid-color emoji patterns

We can create emoji icons by giving emojis a transparent color and text shadow.

color: transparent;
text-shadow: 0 0 black;

Those icons can then be turned into an image that can be used as a background, using SVG.

<svg>
  <foreignObject>
    <!-- The HTML code with emoji -->
  </foreignObject>
</svg>

The SVG can then be referred by the background property using data URL

background: url("data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><!-- SVG code --></svg>");

And, voilá! We get something like this:

background: 
    url("data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><foreignObject width=%22100px%22 height=%22100px%22><div xmlns=%22http://www.w3.org/1999/xhtml%22 style=%22color:transparent;text-shadow: 0 0 %23e42100, -2px 2px 0 black;font-size:70px%22>🏄‍♀️</div></foreignObject></svg>"), 
    white; 
background-size: 60px 60px; 

Other than emojis, it’s also possible to draw CSS shapes and use them as patterns. Emojis are less work, though. Just saying. 

Gradient-colored emoji patterns

Instead of using plain emoji icons, we can use gradient emoji icons. To do that, skip the text shadow on the emojis. Add a gradient background behind them and use background-clip to trim the gradient background to the shape of the emojis. 

color: transparent;
background: linear-gradient(45deg, blue 20%, fuchsia);
background-clip: text; /* Safari requires -webkit prefix */

Then, just as before, use the combination of SVG and data URL to create the background pattern.

Translucent-colored emoji patterns

This is same as using block colored emoji icons. This time, however, we take away the opaqueness of the colors by using rgba() or hsla() values for the text shadow. 

color: transparent;
text-shadow: 20px 10px rgba(0, 255, 0, .3), 
             0 0 red;

SVG-text emoji patterns

We’ve already looked at all the working methods I could think of to create background patterns, but I feel like I should also mention this other technique I tried, which is not as widely supported as I’d hoped.

 I tried placing the emoji in an SVG <text> element instead of the HTML added using <foreignObject>. But I wasn’t able to create a solid shadow behind it in all the browsers.

background: 
  url("data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%221em%22 font-size=%2270%22 fill=%22transparent%22 style=%22text-shadow: 0 0 %23e42100, -2px 2px 5px black, 0 0 6px white; ;%22>🏄‍♀️</text></svg>")

Just in case, I tried using CSS and SVG filters for the shadow as well, thinking that might work. It didn’t. I also tried using the stroke attribute, to at least create an outline for the emoji, but that didn’t work, either. 

CSS element() patterns

I didn’t think of SVG when I first thought of converting emoji icons or CSS shapes into background images. I tried CSS element(). It’s a function that directly converts an HTML element into an image that can be referenced and used. I really like this approach, but browser support is a huge caveat, which is why I’m mentioning it here at the end.

Basically, we can drop an element in the HTML like this:

<div id=snake >🐍</div>

…then pass it into the element() function to use like an image on other elements, like this:

background: 
  -moz-element(#snake), /* Firefox only */
  linear-gradient(45deg, transparent 20px, blue 20px, blue 30px, transparent 30px) 
  white;
background-size: 60px 60px;
background-color: white;

Now that snake emoji is technically an image that we get to include in the pattern.

Again, browser support is spotty, making this approach super experimental.

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

Desktop

ChromeFirefoxIEEdgeSafari
No4*NoNoNo

Mobile / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
No68*NoNo

In this method, the original emoji (or any CSS shape for that matter) used for the background pattern needs to render on screen for it to appear in the background pattern as well. To hide that original emoji, I used mix-blend-mode — it sort of masks out the original emoji in the HTML so it doesn’t show up on the page.


I hope you find the methods in this post useful in one way or another and learned something new in the process! Give them a try. Experiment with different emojis and CSS shapes because gradients, while cool and all, aren’t the only way to make patterns.. The background property takes multiple values, allowing us to think of creative ways to stack things.

The post Creative Background Patterns Using Gradients, CSS Shapes, and Even Emojis appeared first on CSS-Tricks.

Indicating Scroll Position on a Page With CSS

Scrolling is something we all know and do on the web to the extent that it’s an expectation or perhaps even a habit, like brushing our teeth. That’s probably why we don’t put too much thought into designing the scrolling experience — it’s a well-known basic function. In fact, the popular “there is no fold” saying comes from the idea that people know how to scroll and there is no arbitrary line that people don’t go under.

Scroll-based features tend to involve some bespoke concoction of CSS and JavaScript. That’s because there simply aren’t that many native features available to do it. But what if we could accomplish something that only uses CSS? 

Take this ingenious horizontal scrollbar with CSS, for instance. I want to do something similar, but to indicate scrolled sections rather than capture continuous scrolling. In other words, rather than increasing the length of the indicator during scroll, I only want to increase the length when a certain section of the page has been reached.

Like this:

Here’s my plan: Each section carries an indicator that’s undetectable until it reaches the top of the screen. That’s where it becomes visible by changing color and sticks to the top of the viewport.

The exact opposite should happen in reverse: the indicator will follow along when scrolling back up the screen, camouflaging itself back to being undetected to the naked eye.

There are two key parts to this. The first is for the indicator to change color when it’s near the top of the screen. The second is for the indicator to stay put at the top of the screen and come down only when its section is scrolled down to.

The second one is easy to do: we use position: sticky; on our elements. When a page is scrolled, a sticky element sticks to a given position on the screen within its parent container.

That brings us to changing colors. Since the background of an HTML document is white by default, I’m keeping white as the base color for the demo. This means the indicator should look white when it’s over the base color and turn to some other color when it’s over the indicator bar at the top of the screen.

The dashed indicator is currently invisible, but becomes visible when it sticks to the top and blends with the background color of the indicator container.

This is where CSS blend modes come into play. They give us so many options to create a variety of color amalgams. I’m going to go with the overlay value. This one is quite dynamic in nature. I won’t explain the blend in depth (because the CSS-Tricks Alamanac already does a good job of that) but taking this demo into account, I’ll say this: when the background color is white the resulting foreground color is white; and when the background is some other color, the resulting color is darker or lighter, depending on the color it’s mixed with.

The indicator stops in the demo are black. But, because of the blend, we see them as white because they are on a white background. And when they are over the indicator container element, which is a lovely shade of violet, we see a dark violet indicator stop, because we’re mixing the indicator stop’s black with the indicator container’s violet.

Starting with the HTML:

<div id="passageWrapper">
  <strong>Sections Scrolled ↴</strong>
  <!-- Indicator container -->
  <div id="passage"></div>
</div>


<!-- Indicator stop -->
<div class=passageStops></div>


<!-- First Section -->
<div class="sections">
  <!-- Content -->
</div>


<!-- Another indicator stop -->
<div class="passageStops"></div>


<!-- Second Section -->
<div class="sections">
  <!-- Content -->
</div>


<!-- Another indicator stop -->
<div class="passageStops"></div>


<!-- Third Section -->
<div class="sections">
  <!-- Content -->
</div>

Pretty straightforward, right? There’s a sticky container at the very top that holds the indicators when they reach the top.  From there, we have three sections of content, each one topped with an indicator that will stick to the top with the indicator and blend with it.

Here’s the CSS:

.passageStops {
  background-color: black; /* Each indicator stop is black */
  mix-blend-mode: overlay; /* This makes it appear white on a white background */
  width: 33.3%; /* Three sections total, so each section is one-third */
  top: calc(1em + 3px);
}


#passage, 
.passageStops{
  height: 10px;
}


#passageWrapper,
.passageStops {
  position: sticky; /* The container and stops should stick to the top */
  z-index: 1; /* Make sure the indicator and stops stay at the forefront */
}


#passage {
  background: violet; /* Will blend with black to make a darker violet indicator */
  margin: 0 0 20px 0;
}


#passageWrapper{
  background-color: white; /* Make sure we're working with white to hide indicator stops */
  height: 40px;
  top: 0px;
}


/* Each stop will shift one-third the width of the indicator container to cover the whole thing when the last section is reached. */
.passageStops:nth-child(4){ margin-left: 33.3%; }
.passageStops:nth-child(6){ margin-left: 66.6%; }


/* More styling, blah blah. */

The indicators (.passageStops) are black. But the overlay blend mode makes them appear white when it blends with the white background under it. Since there are three sections, each indicator is of one-third width.

The indicators have position: sticky; with a top distance value. This means the indicators will stick once they reach the calculated position from the top of the screen. When that happens, the black indicators that appeared white blend with the violet indicator container, which makes them appear to be a dark violet, representing the new scroll position on the page.

The reverse is also true. When an indicator loses its sticky position, it will move from the violet background of the indicator bar to the white background of the page, hiding it once again… like it was never there!

Here’s the demo again:

That’s it. You can perhaps further experiment with this by having a non-white background with another blend mode, or a gradient for the indicator bar or stops.

The post Indicating Scroll Position on a Page With CSS appeared first on CSS-Tricks.

How I’ve Improved as a Web Developer (and a Person) in 2019

We’re sliding into the roaring twenties of the twenty-first century (cue Jazz music 🎷). It’s important that you and I, as responsible people, follow the tradition of looking back on the past year and reflect on the things that went right and wrong in the hopes of becoming the best version of ourselves in the year ahead.

I never do New Year’s resolutions, except for when I was ten years old and wanted to open a local self-run detective agency by the end of the following year (Scooby Doo was in vogue those days.) But I do reflect on the past this time of year, perhaps as an instinctive response.

Over the years, I’ve improved as a web developer, on my own terms and on my own pace, while learning, unlearning, interpreting and executing what the web technology offers. This post is a reflection of my personal experiences from 2019 and the years before that. I’ll share things I’ve learned that might make us all better web developers heading into 2020. Personal experiences aren’t universal, of course, but it’s sometimes neat to get a look into the things other people are processing and learn vicariously through them.

So here we go.

I spent a lot of time in other people’s code

It was unavoidable because my very first professional project involved updating and upgrading an old application. It was only after some time that I realized I gained wisdom from navigating through code written by others, and also, I developed the guts to voluntarily read others' code and really pay attention to what it’s doing.

It’s not unlike practicing good listening skills. Reading and understanding code written by someone else requires active attention and fighting the temptation to either zone out or inject your own opinion.

What you can try: GitHub is a great place to see a lot of projects. There are so many open source projects out there and they're all readily available to look at and digest. I think many of us have experienced times when we simply grab a project or a tool without really getting under the hood and understanding what it’s actually doing or how it fits into our own work. Taking the time up front is an excellent way to not only learn new things, but to make better decisions in our day-to-day work as well. Don’t understand something? Open an issue in the repo and ask away!

I’d be remiss not to mention CodePen here. Not only can you search for just about any pattern, feature, or function, but it also offers collections of Pens and even topics, both of which are excellent for seeing how different people tackle similar ideas.

I tried new web standards even if I thought I’d never use them

It’s just my curiosity, but I think it has made me feel more comfortable in learning something new. That might be variable fonts, serverless, JAMstack, prefers-color-scheme , prefers-reduced-motion , and subgrid, among many others. Geez, we’ve seen a lot of new things in the last year or two, haven’t we?

What you can try: I think you’re already ahead of this by following sites like CSS-Tricks. There are many technical blogs and writers out there who share with their readers what’s new. Check out the list of people who have contributed to this blog — many of them have personal sites where they’re frequently sharing new things. A Book Apart is also a great resource for standards, especially for those of you who might enjoy a break from the screen. You can find so many gems there, from Expressive Web Design to The New CSS Layout.

I created an archive of my favorite code snippets

There were times when I’d think that I’d remember the oh-so-simple syntax of new code I tried... but it turns out simple things are easier to forget. So I decided to keep them neatly in a digital folder, like in the good ol’ times. This has allowed me to go back and reference code when questions or ideas pop up. Otherwise, I’d have to go back and research all over again.

What you can try: I personally don’t use tools, just save them in a file. That said, Gist is always a nice place to keep snippets. And, hey, CodePen lets you create your own collections as well!

Another idea is to leverage your browser’s bookmarks. Save links liberally. Organize them into logical groupings so they’re easy to find later.

I created an archive of my notes, flow diagrams, and other stuff I scribble on paper

I have a standard paper notepad at my office that I use to jot down everything from ideas for a project I’m working on, layout sketches and notes from things I read. It’s also the place where I often start work, much like the way Chris writes “pseudo code” heading into a code editor.

I have a habit of working out the visual aspects of a web application, and often, even the source code on paper. So, I keep those papers safe for when I might have to refer back. It has helped me out in a pinch.

What you can try: I would be a hypocrite if I recommend any of the online note taking tools, because I’ve never found them convenient, ironically. There are lots of physical notebook options out there. Moleskine is a popular one. Sarah Drasner recommended one when she wrote her own post on learning how to learn.

I recognized when someone’s teaching and I need to be a student

I used to have a bad habit: if someone’s explaining something about code that I might already be familiar with, I would process and interpret what they were saying based on my own personal experiences, way before I learned what they had to say first.

It could be a millennial thing or it could be an industry thing, but I’ve always found that people package everything as something that’s being shared, that somehow I’m sitting in a round table with them and we are dissecting things over a box of pizza. 🍕

I appreciate that people make their content inclusive because we’re all adults here. But it also has stopped me from genuinely learning what they were trying to teach. I skimmed through useful information, but never really cared about the context. On my worst days, I missed the point completely, all because my brain’s resources were divided trying to learn and analyze at the same time.

Active listening and learning has provided a bunch of benefits for me this past year. For example:

  • I hear what people are saying more clearly.
  • I retain what people share with me more easily.
  • It makes the people I’m interacting with feel at ease with me.
  • It opens my mind to new ideas and possibilities I may not have considered.

What you can try: When you want to learn from something, whether it’s an article, a tweet, a podcast episode, a documentation or something else, save it and use it. I learned to grow out of my bad habit this year and have found this to be my flow for learning and retaining from others:

  1. I learn something.
  2. I save it for later (in my archive!).
  3. I try it out when I have the time.
  4. I play around with it more and try improving on it, if needed.
  5. I eat my pizza.

I trusted my own judgement more

This might sound like the exact opposite of what I just said about active listening, but it’s more of a counter-balance to being overly reliant on others. Active listening doesn’t mean we can’t have our own opinions or even continue holding onto them. It simply means we hear and retain information that can inform our own opinions.

A good professional opinion could be such a blessing, but good or bad, the moment I found myself giving too much weight to other people’s opinions, like I’d read a blog post on someone’s development environment and think I have to do the same thing, or worse, that the way I do things is wrong, that’s a terrible feeling (hello Imposter Syndrome) and who needs more stress?

What you can try: Instead of automatically believing that anything you read is the golden standard, try putting up a little guard. In other words, instead of thinking, “This is how I should be doing it,” perhaps say, “Oh, so this is how this person does that.”

I started seeking others' experiences that validates my own

I feel happy when I read or hear fellow web developers share their work experiences and find something that resonates with me on a personal level:

  • “I know! I couldn’t set it up the first time, too!”
  • “Yes, that framework made things slower for me, too!”
  • “No way! I tried to center a floating element, too!”

Seeing that I’m not the only one who makes mistakes or struggles in certain areas makes me feel okay for where my skills are at instead of seeing myself as an unskilled developer who’s prone to mistakes. Chris recently shared his thought process working with flexbox elements — that’s exactly the sort of thing I think we can all relate to.

What you can try: We all bear some responsibility here. Let’s make people feel good when asking questions, even if they seem obvious to us. Share your own mistakes and struggles. The web is a vast and constantly evolving space and we’re all starting from different places.

I made myself the only one who decides what to make on my off-work coding marathons

Like all of you, my learning curve involves coding during my non-working hours. It could be just a new code I’m trying out or a full on side-project.

Seeing others share their side projects inspires me... at least that’s what I want them to do. That hasn't always been the case. They used to make me think I wasn't doing enough. Not enough GitHub repos. Not enough open source contributions. Not enough self-imposed challenges. Not enough WordPress plugins. And, sorry Chris, not enough CodePen demos.

With experience, however, I’ve realized there’s only one human soul that can optimally select what I should be working on, based on my skills, my preferences, my necessities and my circadian rhythm – the ghost under my bed.

Once I understood that, every single awesome and crazy side project people share online truly inspires me — or at least makes me smile, which is even better.

What you can try: Be intentional with your personal time. Prioritize what you want to learn and decide the best way for you to learn it. This post by Jason Rodriguez outlines how he planned to level up his JavaScript skills. Chris shared a mountain of ideas for learning CSS. Sarah also has great tips on prioritizing your personal and professional time.

I stopped drinking coffee

This is not up for discussion, my dear reader. 😀

What you can try: Masala Chai.

I started prioritizing my health

Here’s a very silly story. I sprained my wrists thrice in a month. I think it was a voodoo spell. The point is: it was getting harder for me to work.

I was a bit embarrassed to tell people I couldn’t work because I was injured, so I continued like nothing happened. Each time, the sprain would eventually go away because of the ointment I applied at home, but would return soon enough because I wasn’t properly resting it. At one point, the pain spread to my arms and I’d to immediately take my hands away from the keyboard and rest them on my lap. It scared me.

The next day, I started wearing a wrist cast (well, two) and informed my colleagues and technical director that I needed to take it slow.

I know this story sounds like a very simple and obvious thing — and it was a very simple thing indeed. But I learned an important lesson: Health comes first.

Our job description doesn’t come with health warning stickers, but there are consequences in reality.

What you can try: Take care of your health first. Physical or mental, chronic or acute, mild or severe, internal or external, when your health problems go away, it improves the quality of your life, personally and professionally. If you’re lucky enough to have good health insurance, use it. Schedule an annual physical exam. Listen to your body when it says it’s hungry, thirsty, or simply needs a rest.

I know, easier said than done. But it’s important nonetheless and something worth striving for.

I’ve started sharing my knowledge with others

Not in a way you might assume. I know the consensus is that we learn when we teach but I haven’t personally experienced that. I don’t learn while I teach. Instead, what I've done is focus on how someone I’m teaching could or should learn a particular thing.

  • “Start with the basics.”
  • “Read the documentation.”
  • “Try the demo then proceed to so and so.”

These are some of the statements I found myself repeating to those I’ve mentored.

Those same sentences echo back to me when I've to learn something new. When I teach, I pay attention to how it’s learned. And learning is the one skill that never goes out of date, especially in our line of work.

What you can try: I think you’ll probably have to wait a while before you could do this if you’re just starting out as a web developer, but if you’re even somewhat experienced and meet a wide-eyed newbie, don’t miss your chance to teach. Don't be part of the dark matter. You can teach in a variety of ways, from blogging to making demos. That said, I’ve found real life person-to-person teachable moments to be the most effective.

I realized I can’t read a code once and understand it all. So I use comments.

Here’s my comment about comments: Take them seriously.

Sometimes I can’t even decipher the code that I’ve typed with my two bare hands.

Condensation is a key element of programming languages in addition to something that causes rain. We don’t write, “add one more sheep to the herd.” Instead, we write, i++. Expecting myself to remember and understand everything in one glance simply isn’t practical.

Using well-thought comments cuts back the time it takes me to know what’s happening in the code. This is why I’ve consciously paid attention to using comments this past year. There’s no cost to using them, so go nuts!

What you can try: Take time to go through your code and leave some useful comments each time you’ve coded a module or a feature that works, especially before moving onto what’s next.

I’m not taking working code for granted

I was told margin:auto would center an element. I was told to add return(0) to an onclick event handler. I was also told to use GUID for foreign keys.

I didn’t ask why or how those things worked at the time. I simply did as they said.

I, now, however, know how they work and why I had to use those code.

When I know the basics of a piece of code, it helps me to use the same code or the same logic in scenarios other than the one I learned about it in.

What you can try: Make a quick mental, physical, or digital reminder when you come across a code that you want to know more about. Then remember to go through that list first in your free time. Don’t be afraid to ask someone why code is used a certain way.

I try to mimic extroverted web developers

* takes a deep breath *

I’m an introvert.

My introversion is not so bad that people feel uncomfortable around me. I mean, everybody likes talking to introverts because they mostly listen, right?

Although most of my work is typing in front of a computer I inevitably have to meet people, like clients, users and team members.

Communication is important. And not just the bare minimum.

When you develop a really good relationship with who you work with, your workplace becomes fun. When you develop a good relationship with your users, your work becomes successful; and when you develop a good relationship with your clients, you get more work.

I found there’s no way around it: I had to talk from time to time. I had to put myself out there.

I look at my fellow web developers who are more extroverted for communication pointers. They talk beyond about work. They give their suggestions. They encourage feedback. They drink coffee. And I try to practice that.

What you can try: If you’re an extrovert, I’ve got nothing for you. If you’re an introvert, all I can say is try. And keep trying. And that’s all you ever need to do. We can’t change our personalities, but with some practice and time we’ll learn to manage them better. In fact, it might be worth getting a better understanding of your personality type. Susan Cain’s book Quiet is an interesting (and dense) take on introversion.

I take breaks

I hate this to be true, but I turn into a Shaman soon after I start coding. An unwilling Shaman who gets possessed. The spirit that takes over me likes to only code. It doesn’t like to eat, sleep, talk to people or check Instagram. It’s a very mean spirit.

That’s why I exorcise it regularly to not cloister myself from the world. I pay attention to someone calling me. I leave the desk for tea breaks. I let my laptop’s battery die so I won’t go near it during vacation. I even have a hobby.

I don’t know if taking breaks has improved my performance or not, because I don’t think the mean spirit lacks in performance. I just think it’s good for me to not be always possessed.

What you can try: For those of you with 9-5 job, I would recommend tea breaks at 11AM and 4PM (wow, that came out very specific) And for when you work at home, I suppose you’ll have more things to do, so choose for yourself when you want the break. I like to watch TV, that would be like my ideal break time.


And... that’s it. That’s all the spookiness I could fit into this post. I shared as much of my experience as I could, as well as suggestions you might find helpful. Hope you take something good from it. This might be my final post of the year, so I don’t want to miss this chance to wish you LOTS of good luck as you go into 2020. 🍀

The post How I’ve Improved as a Web Developer (and a Person) in 2019 appeared first on CSS-Tricks.

Weaving One Element Over and Under Another Element

In this post, we’re going to use CSS superpowers to create a visual effect where two elements overlap and weave together. The epiphany for this design came during a short burst of spiritual inquisitiveness where I ended up at The Bible Project’s website. They make really cool animations, and I mean, really cool animations.

My attention, however, deviated from spiritualism to web design as I kept spotting these in-and-out border illustrations.

Screenshot form The Bible Project website.

I wondered if a similar could be made from pure CSS… and hallelujah, it’s possible!

See the Pen
Over and under border design using CSS
by Preethi Sam (@rpsthecoder)
on CodePen.

The principal CSS standards we use in this technique are CSS Blend Modes and CSS Grid.

First, we start with an image and a rotated frame in front of that image.

<div class="design">
  <img src="bird-photo.jpg">
  <div class="rotated-border"></div>
</div>
.design {
  position: relative;
  height: 300px;
  width: 300px;
}

.design > * {
  position: absolute;
  height: 100%;
  width: 100%;
}

.rotated-border {
  box-sizing: border-box;
  border: 15px #eb311f solid;
  transform: rotate(45deg);
  box-shadow: 0 0 10px #eb311f, inset 0 0 20px #eb311f;
}

The red frame is created using border. Its box-sizing is set to include the border size in the dimensions of the box so that the frame is centered around the picture after being rotated. Otherwise, the frame will be bigger than the image and get pulled towards the bottom-right corner.

Then we pick a pair of opposite corners of the image and overlay their quadrants with their corresponding portion in a copy of the same image as before. This hides the red frame in those corners.

We basically need to make a cut portion of the image that looks like below to go on top of the red frame.

The visible two quadrants will lay on top of the .rotated-border element.

So, how do we alter the image so that only two quadrants of the image are visible? CSS Blend Modes! The multiply value is what we’re going to reach for in this instance. This adds transparency to an element by stripping white from the image to reveal what’s behind the element.

Chris has a nice demo showing how a red background shows through an image with the multiply blend mode.

See the Pen
Background Blending
by Chris Coyier (@chriscoyier)
on CodePen.

OK, nice, but what about those quadrants? We cover the quadrants we want to hide with white grid cells that will cause the image to bleed all the way through in those specific areas with a copy of the bird image right on top of it in the sourcecode.

<div id="design">
    <img src="bird-photo.jpg">
    <div class="rotated-border"></div>

    <div class="blend">
      <!-- Copy of the same image -->
      <img src="bird-photo.jpg">
      <div class="grid">
        <!-- Quadrant 1: Top Left -->
        <div></div>
        <!-- Quadrant 2: Top Right -->
        <div data-white></div>
        <!-- Quadrant 3: Bottom Left -->
        <div data-white></div>
        <!-- Quadrant 4: Bottom Right -->
        <div></div>
      </div>
    </div>

</div>
.blend > * {
  position: absolute;
  height: 100%;
  width: 100%;
}

/* Establishes our grid */
.grid {
  display: grid;
  grid: repeat(2, 1fr) / repeat(2, 1fr);
}

/* Adds white to quadrants with this attribute */
[data-white]{
  background-color: white;
}

The result is a two-by-two grid with its top-right and bottom-left quadrants that are filled with white, while being grouped together with the image inside .blend.

To those of you new to CSS Grid, what we’re doing is adding a new .grid element that becomes a "grid" element when we declare display: grid;. Then we use the grid property (which is a shorthand that combines grid-template-columns and grid-template-rows) to create two equally spaced rows and columns. We’re basically saying, "Hey, grid, repeat two equal columns and repeat two equal rows inside of yourself to form four boxes."

A copy of the image and a grid with white cells on top of the red border.

Now we apply the multiply blend mode to .blend using the mix-blend-mode property.

.blend { mix-blend-mode: multiply; }

The result:

As you can see, the blend mode affects all four quadrants rather than just the two we want to see through. That means we can see through all four quadrants, which reveals all of the red rotated box.

We want to bring back the white we lost in top-left and bottom-right quadrants so that they hide the red rotated box behind them. Let’s add a second grid, this time on top of .blend in the sourcecode.

<div id="design">
  <img src="bird-photo.jpg">
  <div class="rotated-border"></div>
    
  <!-- A second grid  -->
  <!-- This time, we're adding white to the image quandrants where we want to hide the red frame  -->
  <div class="grid">
    <!-- Quadrant 1: Top Left -->
    <div data-white></div>
    <!-- Quadrant 2: Top Right -->
    <div></div>
    <!-- Quadrant 3: Bottom Left -->
    <div></div>
    <!-- Quadrant 4: Bottom Right -->
    <div data-white></div>
  </div>

  <div class="blend">
    <img src="bird-photo.jpg">
    <div class="grid">
      <!-- Quadrant 1: Top Left -->
      <div></div>
      <!-- Quadrant 2: Top Right -->
      <div data-white></div>
      <!-- Quadrant 3: Bottom Left -->
      <div data-white></div>
      <!-- Quadrant 4: Bottom Right -->
      <div></div>
    </div>
  </div>

</div>

The result!

Summing up, the browser renders the elements in our demo like this:
​​

  1. ​​At bottommost is the bird image (represented by the leftmost grey shape in the diagram below)
  2. ​​Then a rotated red frame
  3. ​​On top of them is a grid with top-left and bottom-right white cells (corners where we don’t want to see the red frame in the final result)
  4. ​​Followed by a copy of the bird image from before and a grid with top-right and bottom-left white cells (corners where we do want to see the red frame) – both grouped together and given the blending mode, multiply​.

You may have some questions about the approach I used in this post. Let me try to tackle those.

What about using CSS Masking instead of CSS Blend Modes?

For those of you familiar with CSS Masking – using either mask-image or clip-path – it can be an alternative to using blend mode.

I prefer blending because it has better browser support than masks and clipping. For instance, WebKit browsers don't support SVG <mask> reference in the CSS mask-image property and they also provide partial support for clip-path values, especially Safari.

Another reason for choosing blend mode is the convenience of being able to use grid to create a simple white structure instead of needing to create images (whether they are SVG or otherwise).

Then again, I’m fully on board the CSS blend mode train, having used it for knockout text, text fragmentation effect... and now this. I’m pretty much all in on it.

Why did you use grid for the quadrants?

The white boxes needed in the demo can be created by other means, of course, but grid makes things easier for me. For example, we could've leaned on flexbox instead. Use what works for you.

Why use a data-attribute on the grid quadrant elements to make them white?

I used it while coding the demo without thinking much about it – I guess it was quicker to type. I later thought of changing it to a class, but left it as it is because the HTML looked neater that way… at least to me. :)

Is multiply the only blend mode that works for this example?

Nope. If you already know about blend modes then you probably also know you can use either screen, darken, or lighten to get a similar effect. (Both screen and lighten will need black grid cells instead of white.)

The post Weaving One Element Over and Under Another Element appeared first on CSS-Tricks.

The Making of an Animated Favicon

It’s the first thing your eyes look for when you’re switching tabs.

That’s one way of explaining what a favicon is. The tab area is a much more precious screen real-estate than what most assume. If done right, besides being a label with icon, it can be the perfect billboard to represent what’s in or what’s happening on a web page.

The CSS-Tricks Favicon

Favicons are actually at their most useful when you’re not active on a tab. Here’s an example:

Imagine you’re backing up photos from your recent summer vacation to a cloud service. While they are uploading, you’ve opened a new tab to gather details about the places you went on vacation to later annotate those photos. One thing led to the other, and now you’re watching Casey Neistat on the seventh tab. But you can’t continue your YouTube marathon without the anxious intervals of checking back on the cloud service page to see if the photos have been uploaded.

It’s this type of situation where we can get creative! What if we could dynamically change the pixels in that favicon and display the upload progress? That’s exactly what we’ll do in this article.

In supported browsers, we can display a loading/progress animation as a favicon with the help of JavaScript, HTML <canvas> and some centuries-old geometry.

Jumping straight in, we’ll start with the easiest part: adding the icon and canvas elements to the HTML.

<head>
    <link rel="icon" type="image/png" href="" width=32px>
</head>

<body>
    <canvas width=32 height=32></canvas>
</body>

In practical use, you would want to hide the <canvas> on the page, and one way of doing that is with the HTML hidden attribute.

<canvas hidden width=32 height=32></canvas>

I’m going to leave the <canvas> visible on the page for you to see both the favicon and canvas images animate together.

Both the favicon and the canvas are given a standard favicon size: 32 square pixels.

For demo purposes, in order to trigger the loading animation, I’m adding a button to the page which will start the animation when clicked. This also goes in the HTML:

<button>Load</button>

Now let’s set up the JavaScript. First, a check for canvas support:

onload = ()=> {
  canvas = document.querySelector('canvas'),
  context = canvas.getContext('2d');
  if (!!context) {
      /* if canvas is supported */
  }
};

Next, adding the button click event handler that will prompt the animation in the canvas.

button = document.querySelector('button');
button.addEventListener('click', function() { 
    /* A variable to track the drawing intervals */
    n = 0, 
    /* Interval speed for the animation */
    loadingInterval = setInterval(drawLoader, 60); 
});

drawLoader will be the function doing the drawing at intervals of 60 milliseconds each, but before we code it, I want to define the style of the lines of the square to be drawn. Let’s do a gradient.

/* Style of the lines of the square that'll be drawn */
let gradient = context.createLinearGradient(0, 0, 32, 32);
gradient.addColorStop(0, '#c7f0fe');
gradient.addColorStop(1, '#56d3c9');
context.strokeStyle = gradient;
context.lineWidth = 8;

In drawLoader, we’ll draw the lines percent-wise: during the first 25 intervals, the top line will be incrementally drawn; in second quarter, the right line will be drawn; and so forth.

The animation effect is achieved by erasing the <canvas> in each interval before redrawing the line(s) from previous interval a little longer.

During each interval, once the drawing is done in the canvas, it’s quickly translated to a PNG image to be assigned as the favicon.

function drawLoader() {
  with(context) {
    clearRect(0, 0, 32, 32);
    beginPath();
    /* Up to 25% */
    if (n<=25){ 
      /*
        (0,0)-----(32,0)
      */
      // code to draw the top line, incrementally
    }
    /* Between 25 to 50 percent */
    else if(n>25 && n<=50){ 
      /*
        (0,0)-----(32,0)
                  |
                  |
                  (32,32)
      */
      // code to draw the top and right lines.
    }
    /* Between 50 to 75 percent */
    else if(n>50 && n<= 75){ 
      /*
        (0,0)-----(32,0)
                  |
                  |
        (0,32)----(32,32)
      */
      // code to draw the top, right and bottom lines.
    }
      /* Between 75 to 100 percent */
    else if(n>75 && n<=100){
      /*
        (0,0)-----(32,0)
            |      |
            |      |
        (0,32)----(32,32)
      */
      // code to draw all four lines of the square.
    }
    stroke();
  }
  // Convert the Canvas drawing to PNG and assign it to the favicon
  favicon.href = canvas.toDataURL('image/png');
  /* When finished drawing */
  if (n === 100) {
    clearInterval(loadingInterval);
    return;
  }
  // Increment the variable used to keep track of the drawing intervals
  n++;
}

Now to the math and the code for drawing the lines.

Here’s how we incrementally draw the top line at each interval during the first 25 intervals:

n = current interval, 
x = x-coordinate of the line’s end point at a given interval.
(y-coordinate of the end point is 0 and start point of the line is 0,0)

At the completion of all 25 intervals, the value of x is 32 (the size of the favicon and canvas.)

So...

x/n = 32/25
x = (32/25) * n

The code to apply this math and draw the line is:

moveTo(0, 0); lineTo((32/25)*n, 0);

For the next 25 intervals (right line), we target the y coordinate similarly.

moveTo(0, 0); lineTo(32, 0);
moveTo(32, 0); lineTo(32, (32/25)*(n-25));

And here’s the instruction to draw all four of the lines with the rest of the code.

function drawLoader() {
  with(context) {
    clearRect(0, 0, 32, 32);
    beginPath();
    /* Up to 25% of the time assigned to draw */
    if (n<=25){ 
      /*
        (0,0)-----(32,0)
      */
      moveTo(0, 0); lineTo((32/25)*n, 0);
    }
    /* Between 25 to 50 percent */
    else if(n>25 && n<=50){ 
      /*
        (0,0)-----(32,0)
                  |
                  |
                  (32,32)
      */
      moveTo(0, 0); lineTo(32, 0);
      moveTo(32, 0); lineTo(32, (32/25)*(n-25));
    }
    /* Between 50 to 75 percent */
    else if(n>50 && n<= 75){ 
      /*
        (0,0)-----(32,0)
                  |
                  |
        (0,32)----(32,32)
      */
      moveTo(0, 0); lineTo(32, 0);
      moveTo(32, 0); lineTo(32, 32);
      moveTo(32, 32); lineTo(-((32/25)*(n-75)), 32);
    }
      /* Between 75 to 100 percent */
    else if(n>75 && n<=100){
      /*
        (0,0)-----(32,0)
            |      |
            |      |
        (0,32)----(32,32)
      */
      moveTo(0, 0); lineTo(32, 0);
      moveTo(32, 0); lineTo(32, 32);
      moveTo(32, 32); lineTo(0, 32);
      moveTo(0, 32); lineTo(0, -((32/25)*(n-100)));
    }
    stroke();
  }

  // Convert the Canvas drawing to PNG and assign it to the favicon
  favicon.href = canvas.toDataURL('image/png');
  /* When finished drawing */
  if (n === 100) {
      clearInterval(loadingInterval);
      return;
  }
  // Increment the variable used to keep track of drawing intervals
  n++;
}

That’s all! You can see and download the demo code from this GitHub repo. Bonus: if you’re looking for a circular loader, check out this repo.

You can use any shape you want, and if you use the fill attribute in the canvas drawing, that’ll give you a different effect.

The post The Making of an Animated Favicon appeared first on CSS-Tricks.

A Few Functional Uses for Intersection Observer to Know When an Element is in View

You might not know this, but JavaScript has stealthily accumulated quite a number of observers in recent times, and Intersection Observer is a part of that arsenal. Observers are objects that spot something in real-time — like birdwatchers going to their favorite place to sit and wait for the birds to come.

Different observers observe different things (not everyone watches hawks).

The very first observer I came to know was the Mutation Observer that looks for changes to the DOM tree. It was a one-of-a-kind at the time, but now we have many more observers.

Intersection Observer observes the "intersection" (i.e. the passing across) of an element through one of its ancestor elements or the area on screen where the page is visible (aka the viewport).

It’s sort of like watching a train pass through a station. You can see when the train comes in, when it leaves, and how long it was stationary.

Knowing when an element is about to come into view, if it has gone out of view, or how long it’s been since it came into view all have useful applications. So, we’ll see some of those use cases now — right after seeing the code for creating an IntersectionObserver object by way of the Intersection Observer API.

A quick overview of IntersectionObserver

The Intersection Observer API has already gained wide support at the time of this writing.

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

Desktop

ChromeOperaFirefoxIEEdgeSafari
584555No1612.1

Mobile / Tablet

iOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox
12.246No677466

But if you want to check whether Intersection Observer is supported while you’re working with it, you could see if the property IntersectionObserver exists in the window object:

if(!!window.IntersectionObserver){}
/* or */
if('IntersectionObserver' in window){}

OK, now for a look at the object creation:

var observer = new IntersectionObserver(callback, options);

The IntersectionObserver object’s constructor takes two parameters. The first one is a callback function that’s executed once the observer notices an intersection and has asynchronously delivered some data about that intersection.

The second (optional) parameter is options, an object with information to define what’s going to be the "intersection." We may not want to know when an element is about to come into view, but only when it’s fully visible. Something like that is defined through the options parameter.

Options has three properties:

  • root - The ancestor element/viewport that the observed element will intersect. Think of it as the train station that the train will intersect.
  • rootMargin - A perimeter of the root element, shrinking or growing the root element’s area to watch out for intersection. It’s similar to the CSS margin property.
  • threshold - An array of values (between 0 and 1.0), each representing the distance an element has intersected into or crossed over in the root at which the callback is to be triggered.

Let’s say our threshold is 0.5. The callback is triggered when the element is in or passes its half-visible threshold. If the value is [0.3, 0.6], then the callback is triggered when the element is in or passes its 30% visible threshold and also, its 60% visible threshold.

That’s enough of the theory now. Let’s see some demos. First up, lazy loading.

Use Case 1: Lazy loading images

See the Pen
Intersection Observer - Lazy Load
by Preethi Sam (@rpsthecoder)
on CodePen.

To see the loading at the mark, view this webpage since the embedded demo doesn't show that.

CSS-Tricks has thoroughly covered lazy loading in before and it’s typically done like this: display a lightweight placeholder where images are intended, then swap them out for the intended images as they come (or are about to come) into view. Believe me, there’s nothing lazy about implementing this — that is, until we get something native to work with.

We’ll apply the same mechanics. First, we’ve a bunch of images and have defined a placeholder image to display initially. We’re using a data attribute carrying the URL of the original image to be shown that defines the actual image to load when it comes into view.

<img src="placeholder.png" data-src="img-1.jpg">
<img src="placeholder.png" data-src="img-2.jpg">
<img src="placeholder.png" data-src="img-3.jpg">
<!-- more images -->

The rest is scripting.

let observer = new IntersectionObserver(
(entries, observer) => { 
  entries.forEach(entry => {
    /* Here's where we deal with every intersection */
  });
}, 
{rootMargin: "0px 0px -200px 0px"});

The callback function above is an arrow function (though you can use a normal function instead).

The callback function receives two parameters: a set of entries carrying the information about each intersection and the observer itself. Those entries can be filtered or looped through so we can then deal with the intersection entries that we want. As for the options, I’ve only provided the rootMargin value, letting the root and threshold properties fall into their default values.

The root default is the viewport and threshold default is 0 — which can be roughly translated to "ping me the very moment that the element appears in the viewport!"

The oddity, though, is that I reduced the viewport’s observation area by two hundred pixels at the bottom using rootMargin. We wouldn’t typically do this for lazy loading. Instead, we might increase the margin or let it default. But reducing isn’t something we would usually do in this situation. I did it only because I want to demonstrate the original images loading at the threshold in the observed area. Otherwise, all the action would happen out of view.

When the image intersects the viewport’s observer area (which is 200px above the bottom in the demo), we replace the placeholder image with the actual image.

let observer = new IntersectionObserver(
(entries, observer) => { 
entries.forEach(entry => {
    /* Placeholder replacement */
    entry.target.src = entry.target.dataset.src;
    observer.unobserve(entry.target);
  });
}, 
{rootMargin: "0px 0px -200px 0px"});

entry.target is the element observed by the observer. In our case, those are the image elements. Once the placeholder is replaced in an image element, we don’t have to observe it anymore, so we call the observer’s unobserve method for it.

Now that the observer is ready, it’s time to start observing all the images by using its observer method:

document.querySelectorAll('img').forEach(img => { observer.observe(img) });

That’s it! we’ve lazy loaded the images. Onto the next demo.

Use Case 2: Auto-pause video when it’s out of view

Let’s say we’re watching a video on YouTube and (for whatever reason) we want to scroll down to read the comments. I don’t know about you, but I don’t usually pause the video first before doing that, which means I miss some of the video while I’m browsing.

Wouldn’t it be nice if the video paused for us when we scroll away from it? It would be even nicer if the video resumed when it’s back in view so there’s no need to hit Play or Pause at all.

Intersection Observer can certainly do that.

See the Pen
IntersectionObserver: auto-pause out of view video
by Preethi Sam (@rpsthecoder)
on CodePen.

Here’s our video in the HTML:

<video src="OSRO-animation.mp4" controls=""></video>

Here’s how we toggle between play and pause:

let video = document.querySelector('video');
let isPaused = false; /* Flag for auto-paused video */
let observer = new IntersectionObserver((entries, observer) => { 
  entries.forEach(entry => {
    if(entry.intersectionRatio!=1  && !video.paused){
      video.pause(); isPaused = true;
    }
    else if(isPaused) {video.play(); isPaused=false}
  });
}, {threshold: 1});
observer.observe(video);

Before I show you how we’re pausing and playing the video during each intersection (i.e. entry), I want to bring your attention to the threshold property of the options.

Th threshold has a value of 1. Both root and rootMargin will default. This is the same as saying, "hey, let me know as soon the element is fully visible on the viewport."

Once the intersection happens and the callback is triggered, we pause or play the video based on this logic:

A flow chart for toggling play and pause on a video, where if video not fully visible and not paused, then isPaused is true. But if video was auto-paused, then IsPaused is false.

I have not called unobserve for the video, so the observer keeps observing the video and pauses every time it goes out of view.

Use Case 3: See how much content is viewed

This can be interpreted and implemented in many ways depending on what your content is and the way you prefer to measure how much of it has been viewed.

For a simple example, we’ll observe the last paragraph of every article in a list of articles on a page. Once an article’s last paragraph becomes fully visible, we will consider that article read — like how we might say that seeing the last coach of a train counts as having seen the whole train.

Here’s a demo that shows two articles on a page, each containing a number of paragraphs.

See the Pen
IntersectionObsever: content viewed
by Preethi Sam (@rpsthecoder)
on CodePen.

Our simplified HTML is something like this:

<div id="count"><!-- The place where "number of articles viewed" is displayed --></div>

<h2>Article 1</h2>
<article>
  <p><!-- Content --></p>
  <!-- More paragraphs -->
</article>
<h2>Article 2</h2>
<article>
  <p><!-- Content --></p>
  <!-- More paragraphs -->
</article>
<!-- And so on... -->
let n=0; /* Total number of articles viewed */
let count = document.querySelector('#count');
let observer = new IntersectionObserver((entries, observer) => { 
  entries.forEach(entry => {
    if(entry.isIntersecting){
      count.textContent= `articles fully viewed - ${++n}`; 
      observer.unobserve(entry.target);
    }
  });
}, {threshold: 1});

document.querySelectorAll('article > p:last-child').forEach(p => { observer.observe(p) });

During each intersection — the full view of the last paragraph of an article — we’re incrementing a count: n, that represents the total number of articles read. Then we display that number above the list of articles.

Once we’ve counted in an intersection of the last paragraph, it doesn’t need to be observed anymore, so we call unobserve for it.

Thanks for observing along!

That’s it for the examples we’re going to look at together for this post. You probably get the idea of how using it is, to be able to observe elements and trigger events based on where they intersect the viewport.

That said, it’s worth using caution when making visual changes based on the intersection data obtained through the observer. Sure, Intersection Observer is hassle free when it comes to logging intersection data. But when it’s being used to make onscreen changes, we need to ensure the changes aren’t lagging, which is a possibility because we’re basically making changes based on data retrieved asynchronously. That might require a little bit of time to load.

As we saw, each intersection entry has a set of properties conveying information about the intersection. I didn’t cover all of them in this post, so be sure to review them.

The post A Few Functional Uses for Intersection Observer to Know When an Element is in View appeared first on CSS-Tricks.

Extracting Text from Content Using HTML Slot, HTML Template and Shadow DOM

Chapter names in books, quotes from a speech, keywords in an article, stats on a report — these are all types of content that could be helpful to isolate and turn into a high-level summary of what's important.

For example, have you seen the way Business Insider provides an article's key points before getting into the content?

That’s the sort of thing we're going to do, but try to extract the high points directly from the article using HTML Slot, HTML Template and Shadow DOM.

These three titular specifications are typically used as part of Web Components — fully functioning custom element modules meant to be reused in webpages.

Now, what we aim to do, i.e. text extraction, doesn’t need custom elements, but it can make use of those three technologies.

There is a more rudimentary approach to do this. For example, we could extract text and show the extracted text on a page with some basic script without utilizing slot and template. So why use them if we can go with something more familiar?

The reason is that using these technologies permits us a preset markup code (also optionally, style or script) for our extracted text in HTML. We’ll see that as we proceed with this article.

Now, as a very watered-down definition of the technologies we’ll be using, I’d say:

  • A template is a set of markup that can be reused in a page.
  • A slot is a placeholder spot for a designated element from the page.
  • A shadow DOM is a DOM tree that doesn’t really exist on the page till we add it using script.

We’ll see them in a little more depth once we get into coding. For now, what we’re going to make is an article that follows with a list of key points from the text. And, you probably guessed it, those key points are extracted from the article text and compiled into the key points section.

See the Pen
Text Extraction with HTML Slot and HTML Template
by Preethi Sam (@rpsthecoder)
on CodePen.

The key points are displayed as a list with a design in between the points. So, let’s first create a template for that list and designate a place for the list to go.

<article><!-- Article content --></article>

<!-- Section where the extracted keypoints will be displayed -->
<section id='keyPointsSection'>
  <h2>Key Points:</h2>
  <ul><!-- Extracted key points will go in here --></ul>
</section>

<!-- Template for the key points list -->
<template id='keyPointsTemplate'>
  <li><slot name='keyPoints'></slot></li>
  <li style="text-align: center;">&#x2919;&mdash;&#x291a;</li>
</template>

What we’ve got is a semantic <section> with a <ul> where the list of key points will go. Then we have a <template> for the list items that has two <li> elements: one with a <slot> placeholder for the key points from the article and another with a centered design.

The layout is arbitrary. What’s important is placing a <slot> where the extracted key points will go. Whatever’s inside the <template> will not be rendered on the page until we add it to the page using script.

Further, the markup inside <template> can be styled using inline styles, or CSS enclosed by <style>:

<template id='keyPointsTemplate'>
    <li><slot name='keyPoints'></slot></li>
    <li style="text-align: center;">&#x2919;&mdash;&#x291a;</li>
    <style>
        li{/* Some style */}
    </style>
</template>

The fun part! Let’s pick the key points from the article. Notice the value of the name attribute for the <slot> inside the <template> (keyPoints) because we’ll need that.

<article>
  <h1>Bears</h1>
  <p>Bears are carnivoran mammals of the family Ursidae. <span><span slot='keyPoints'>They are classified as caniforms, or doglike carnivorans</span></span>. Although only eight species of bears <!-- more content --> and partially in the Southern Hemisphere. <span><span slot='keyPoints'>Bears are found on the continents of North America, South America, Europe, and Asia</span></span>.<!-- more content --></p>
  <p>While the polar bear is mostly carnivorous, <!-- more content -->. Bears use shelters, such as caves and logs, as their dens; <span><span slot='keyPoints'>Most species occupy their dens during the winter for a long period of hibernation</span></span>, up to 100 days.</p>
  <!-- More paragraphs --> 
</article>

The key points are wrapped in a <span> carrying a slot attribute value ("keyPoints") matching the name of the <slot> placeholder inside the <template>.

Notice, too, that I’ve added another outer <span> wrapping the key points.

The reason is that slot names are usually unique and are not repeated, because one <slot> matches one element using one slot name. If there’re more than one element with the same slot name, the <slot> placeholder will be replaced by all those elements consecutively, ending in the last element being the final content at the placeholder.

So, if we matched that one single <slot> inside the <template> against all of the <span> elements with the same slot attribute value (our key points) in a paragraph or the whole article, we’d end up with only the last key point present in the paragraph or the article in place of the <slot>.

That’s not what we need. We need to show all the key points. So, we’re wrapping the key points with an outer <span> to match each of those individual key points separately with the <slot>. This is much more obvious by looking at the script, so let’s do that.

const keyPointsTemplate = document.querySelector('#keyPointsTemplate').content;
const keyPointsSection = document.querySelector('#keyPointsSection > ul');
/* Loop through elements with 'slot' attribute */
document.querySelectorAll('[slot]').forEach((slot)=>{
  let span = slot.parentNode.cloneNode(true);
  span.attachShadow({  mode: 'closed' }).appendChild(keyPointsTemplate.cloneNode(true));
  keyPointsSection.appendChild(span);
});

First, we loop through every <span> with a slot attribute and get a copy of its parent (the outer <span>). Note that we could also loop through the outer <span> directly if we’d like, by giving them a common class value.

The outer <span> copy is then attached with a shadow tree (span.attachShadow) made up of a clone of the template’s content (keyPointsTemplate.cloneNode(true)).

This "attachment" causes the <slot> inside the template’s list item in the shadow tree to absorb the inner <span> carrying its matching slot name, i.e. our key point.

The slotted key point is then added to the key points section at the end of the page (keyPointsSection.appendChild(span)).

This happens with all the key points in the course of the loop.

That’s really about it. We’ve snagged all of the key points in the article, made copies of them, then dropped the copies into the list template so that all of the key points are grouped together providing a nice little CliffsNotes-like summary of the article.

Here's that demo once again:

See the Pen
Text Extraction with HTML Slot and HTML Template
by Preethi Sam (@rpsthecoder)
on CodePen.

What do you think of this technique? Is it something that would be useful in long-form content, like blog posts, news articles, or even Wikipedia entries? What other use cases can you think of?

The post Extracting Text from Content Using HTML Slot, HTML Template and Shadow DOM appeared first on CSS-Tricks.

Using the Little-Known CSS element() Function to Create a Minimap Navigator

W3C’s CSS Working Group often gives us brilliant CSS features to experiment with. Sometimes we come across something so cool that sticks a grin on our face, but it vanishes right away because we think, “that’s great, but what do I do with it?” The element() function was like that for me. It’s a CSS function that takes an element on the page and presents it as an image to be displayed on screen. Impressive, but quixotic.

Below is a simple example of how it works. It’s currently only supported in Firefox, which I know is a bummer. But stick with me and see how useful it can be.

<div id="ele">
  <p>Hello World! how're you?<br>I'm not doing that<br>great. Got a cold &#x1F637;</p>
</div>
<div id="eleImg"></div>
#eleImg {
  background: -moz-element(#ele) no-repeat center / contain; /* vendor prefixed */
}

The element() function (with browser prefix) takes the id value of the element it’ll translate into an image. The output looks identical to the appearance of the given element on screen.

When I think of element()’s output, I think of the word preview. I think that’s the type of use case that gets the most out of it: where we can preview an element before it’s shown on the page. For example, the next slide in a slideshow, the hidden tab, or the next photo in a gallery. Or... a minimap!

A minimap is a mini-sized preview of a long document or page, usually shown at on one side of the screen or another and used to navigate to a corresponding point on that document.

You might have seen it in code editors like Sublime Text.

The minimap is there on the right.

CSS element() is useful in making the “preview” part of the minimap.

Down below is the demo for the minimap, and we will walk through its code after that. However, I recommend you see the full-page demo because minimaps are really useful for long documents on large screens.

If you’re using a smartphone, remember that, according to the theory of relativity, minimaps will get super mini in mini screens; and no, that’s not really what the theory of relativity actually says, but you get my point.

See the Pen Minimap with CSS element() & HTML input range by Preethi Sam (@rpsthecoder) on CodePen.

A screenshot of the final result of the demo. It consists of a large block of styled paragraph text with a

If you’re designing the minimap for the whole page, like for a single page website, you can use the document body element for the image. Otherwise, targeting the main content element, like the article in my demo, also works.

<div id="minimap"></div>
<div id="article"> <!-- content --> </div>
#minimap {
  background: rgba(254,213,70,.1) -moz-element(#article) no-repeat center / contain;
  position: fixed; right: 10px; top: 10px; /* more style */
}

For the minimap’s background image, we feed the id of the article as the parameter of element() and, like with most background images, it’s styled to not repeat (no-repeat) and fit inside (contain) and at center of the box (center) where it’s displayed.

The minimap is also fixed to the screen at top right of the viewport.

Once the background is ready, we can add a slider on top of it and it will serve to operate the minimap scrolling. For the slider, I went with input: range, the original, uncomplicated, and plain HTML slider.

<div id="minimap">
  <input id="minimap-range" type="range" max="100" value="0">
</div>
#minimap-range {
  /* Rotating the default horizontal slider to vertical */
  transform: translateY(-100%) rotate(90deg);
  transform-origin: bottom left;
  background-color: transparent;  /* more style */
}

#minimap-range::-moz-range-thumb {
  background-color: dodgerblue; 
  cursor: pointer; /* more style */
}

#minimap-range::-moz-range-track{
  background-color: transparent;
}

Not entirely uncomplicated because it did need some tweaking. I turned the slider upright, to match the minimap, and applied some style to its pseudo elements (specifically, the thumb and track) to replace their default styles. Again, we’re only concerned about Firefox at the moment since we’re dealing with limited support.

All that’s left is to couple the slider’s value to a corresponding scroll point on the page when the value is changed by the user. That takes a sprinkle of JavaScript, which looks like this:

onload = () => {
  const minimapRange = document.querySelector("#minimap-range");
  const minimap = document.querySelector("#minimap");
  const article = document.querySelector("#article");
  const $ = getComputedStyle.bind();
  
  // Get the minimap range width multiplied by the article height, then divide by the article width, all in pixels.
  minimapRange.style.width = minimap.style.height = 
    parseInt($(minimapRange).width) * parseInt($(article).height) / parseInt($(article).width) + "px";
  
  // When the range changes, scroll to the relative percentage of the article height    
  minimapRange.onchange = evt => 
    scrollTo(0, parseInt($(article).height) * (evt.target.value / 100));
};

The dollar sign ($) is merely an alias for getComputedStyle(), which is the method to get the CSS values of an element.

It’s worth noting that the width of the minimap is already set in the CSS, so we really only need to calculate its height. So, we‘re dealing with the height of the minimap and the width of the slider because, remember, the slider is actually rotated up.

Here’s how the equation in the script was determined, starting with the variables:

  • x1 = height of minimap (as well as the width of the slider inside it)
  • y1 = width of minimap
  • x2 = height of article
  • y2 = width of article
x1/y1 = x2/y2
x1 = y1 * x2/y2
    
height of minimap = width of minimap * height of article / width of article

And, when the value of the slider changes (minimapRange.onchange), that’s when the ScrollTo() method is called to scroll the page to its corresponding value on the article. 💥

Fallbacks! We need fallbacks!

Obviously, there are going to be plenty of times when element() is not supported if we were to use this at the moment, so we might want to hide the minimap in those cases.

We check for feature support in CSS:

@supports (background: element(#article)) or (background: -moz-element(#article)){
  /* fallback style */
}

...or in JavaScript:

if(!CSS.supports('(background: element(#article)) or (background: -moz-element(#article))')){
  /* fallback code */
}

If you don’t mind the background image being absent, then you can still keep the slider and apply a different style on it.

There are other slick ways to make minimaps that are floating out in the wild (and have more browser support). Here’s a great Pen by Shaw:

See the Pen
Mini-map Progress Tracker & Scroll Control
by Shaw (@shshaw)
on CodePen.

There are also tools like pagemap and xivimap that can help. The element() function is currently specced in W3C’s CSS Image Values and Replaced Content Module Level 4. Defintely worth a read to fully grasp the intention and thought behind it.

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

Desktop

ChromeOperaFirefoxIEEdgeSafari
NoNo4*NoNoNo

Mobile / Tablet

iOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox
NoNoNoNoNo64*

Psst! Did you try selecting the article text in the demo? See what happens on the minimap. 😉

The post Using the Little-Known CSS element() Function to Create a Minimap Navigator appeared first on CSS-Tricks.