Tag: Reveal

Checkerboard Reveal

Back when I was 10, I remember my cousin visiting our house. He was (and still is) a cool kid, the kind who’d bring his own self-programmed chess game on a floppy disk. And his version of chess was just as cool as him because a piece of the board would disappear after each move.

Even cooler? Each disappearing piece of the game board revealed a pretty slick picture.

It was a really hard game.

I thought that same sort of idea would make for some pretty slick UI. Except, maybe instead of requiring user interaction to reveal the background, it could simply play as an animation. Here’s where I landed:

The idea’s pretty simple and there are lots of other ways to do it, but here’s the rabbit trail I followed…

First, I created some markup

The image can be handled as a background in CSS on the <body>, or some <div> that’s designed to be a specific size. So, no need to deal with that just yet.

But the checkerboard is interesting. That’s a pattern that has CSS Grid written all over it, so I went with an element to act as a grid container with a bunch of other <div> elements right inside it. I don’t know how many tiles/squares/whatever a legit chess board has, so I just chose the number seven out of thin air and squared it to get 49 total squares.

<div class="grid">   <div></div>   <!-- etc. -->   <div></div> </div>

Yeah, writing out all those divs is a pain and where JavaScript could certainly help. But if I’m just experimenting and only need the developer convenience, then that’s where using Haml can help instead:

.grid   - 49.times do     %div

It all comes out the same in the end. Either way, that gave me all the markup I needed to start styling!

Setting the background image

Again, this can happen as a background-image on the <body> or some other element, depending on how this is being used — just as long as it covers the entire space. Since I needed a grid container anyway, I decided to use that.

.checkerboard {   background-image: url('walrus.jpg');   background-size: cover;   /* Might need other properties to position the image just right */ }

The gradient is part of the raster image file, but I could’ve gotten clever with some sort of overlay on the <body> using a pseudo-element, like :after. Heck, that’s a widely used technique right here on the current design of CSS-Tricks.

Styling the grid

And yes, I went with CSS Grid. Making a 7×7 grid is pretty darn easy that way.

.checkerboard {   background-image: url('walrus.jpg');   background-size: cover;   display: grid;   grid-template-columns: repeat(7, 1fr);   grid-template-rows: repeat(7, 1fr); }

I imagine this will be a lot better once we see aspect-ratio widely supported, at least if I correctly understand it. The problem I have right now is that the grid doesn’t stay in any sort of proportion. That means the checkerboard’s tiles get all squishy and such at different viewport sizes. Boo. There are hacky little things we can do in the meantime, if that’s super important, but I decided to leave it as is.

Styling the tiles

They alternate between white and a dark shade of grey, so:

.checkerboard > div {   background-color: #fff; } .checkerboard > div:nth-child(even) {   background-color: #2f2f2f; }

Believe it or not, our markup and styling is done! All that’s left is…

Animating the tiles

All the animation needs to do is transition each tile from opacity: 1; to opacity: 0; and CSS Animations are perfect for that.

@keyframes poof {   to {     opacity: 0;   } }

Great! I didn’t even need to set a starting keyframe! All I had to do was call the animation on the tiles.

.checkerboard > div {   animation-name: poof;   animation-duration: 0.25s;   animation-fill-mode: forwards;   background: #fff; }

Yes, I could have used the animation shorthand property here, but I often find it easier to break its constituent properties out individually because… well, there’s so gosh darn many of them and things get hard to read and identify on a single line.

If you’re wondering why animation-fill-mode is needed here, it’s because it prevents the animation from looping back to the start of the animation when set to forwards. In other words, each tile will stay at opacity: 0; when the animation finishes rather than coming back into view.

I really, really wanted to do something smart and clever to stagger the animation-delay of the tiles, but I hit a bunch of walls and ultimately decided to ditch my effort to go 100% vanilla CSS for some light SCSS. That way, I could loop through all of the tiles and offset the animation for each one with a pretty standard function. So, sorry for the abrupt switch! That was just part of the journey.

$ columns: 7; $ rows: 7; $ cells: $ columns * $ rows;  @for $ i from 1 through $ cells {   .checkerboard > div:nth-child(#{$ i}) {     animation-delay: (random($ cells) / $ columns) + s;   } }

Let’s break that down:

  • There are variables for the number of grid columns ($ columns), grid rows ($ rows), and total number of cells ($ cells). That last one is the product of multiplying the first two. If we know we are always working in with a grid that’s a perfect square, then we could refactor that a bit to calculate the number cells with exponents.
  • Then for every instance of cells between 1 and the total number of $ cells (which is 49 in this case), each individual tile gets an animation-delay based on its :nth-child() value. So, the first tile is div:nth-child(1), then div:nth-child(2), and so on. View the compiled CSS in the demo and you’ll see how it all breaks out.
.checkerboard > div:nth-child(1) {} .checkerboard > div:nth-child(2) {} /* etc. */
  • Finally, the animation-delay is a calculation that takes a random number between 1 and the total number of $ cells, divided by the number of $ columns with seconds appended to the value. Is this the best way to do it? I dunno. It comes down to playing around with things a bit and landing on something that feels “right” to you. This felt “right” to me.

I really, really wanted to get creative and use CSS Custom Properties instead of resorting to SCSS. I like that custom properties and values can be updated client-side, as opposed to SCSS where the calculated values are compiled on build and stay that way. Again, this is exactly where I would be super tempted to reach for JavaScript instead. But, I made my bed and have to lie in it.

If you peeked at the compiled CSS earlier, then you would have seen the calculated values:

/* Yes, Autoprefixer is in there... */ .checkerboard > div:nth-child(1) {   -webkit-animation-delay: 4.5714285714s;           animation-delay: 4.5714285714s; }  .checkerboard > div:nth-child(2) {   -webkit-animation-delay: 5.2857142857s;           animation-delay: 5.2857142857s; }  .checkerboard > div:nth-child(3) {   -webkit-animation-delay: 2.7142857143s;           animation-delay: 2.7142857143s; }  .checkerboard > div:nth-child(4) {   -webkit-animation-delay: 1.5714285714s;           animation-delay: 1.5714285714s; }

Hmm, perhaps that animation should be optional…

Some folks are sensitive to motion and movement, so it’s probably a good idea to switch things up so the tiles are only styled and animation if — and only if — a user prefers it. We have a media query for that!

@media screen and (prefers-reduced-motion: no-preference) {   .checkerboard > div {     animation-name: poof;     animation-duration: 0.25s;     animation-fill-mode: forwards;     background: #fff;   }   .checkerboard > div:nth-child(even) {     background: #2f2f2f;   } }

There you have it!

Here’s that demo one more time:

The post Checkerboard Reveal appeared first on CSS-Tricks.

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



Menu Reveal By Page Rotate Animation

There are many different approaches to menus on websites. Some menus are persistent, always in view and display all the options. Other menus are hidden by design and need to be opened to view the options. And there are even additional approaches on how hidden menus reveal their menu items. Some fly out and overlap the content, some push the content away, and others will do some sort of full-screen deal.

Whatever the approach, they all have their pros and cons and the right one depends on the situation where it’s being used. Frankly, I tend to like fly-out menus in general. Not for all cases, of course. But when I’m looking for a menu that is stingy on real estate and easy to access, they’re hard to beat.

What I don’t like about them is how often they conflict with the content of the page. A fly-out menu, at best, obscures the content and, at worst, removes it completely from the UI.

I tried taking another approach. It has the persistence and availability of a fixed position as well as the space-saving attributes of a hidden menu that flies out, only without removing the user from the current content of the page.

Here’s how I made it.

The toggle

We’re building a menu that has two states — open and closed — and it toggles between the two. This is where the Checkbox Hack comes into play. It’s perfect because a checkbox has two common interactive states — checked and unchecked (there’s also the indeterminate) — that can be used to trigger those states.

The checkbox is hidden and placed under the menu icon with CSS, so the user never sees it even though they interact with it. Checking the box (or, ahem, the menu icon) reveals the menu. Unchecking it hides it. Simple as that. We don’t even need JavaScript to do the lifting!

Of course, the Checkbox Hack isn’t the only way to do this, and if you want to toggle a class to open and close the menu with JavaScript, that’s absolutely fine.

It’s important the checkbox precedes the main content in the source code, because the :checked selector we’re going to ultimately write to make this work needs to use a sibling selector. If that’ll cause layout concerns for you, use Grid or Flexbox for your layouts as they are source order independent, like how I used its advantage for counting in CSS.

 The checkbox’s default style (added by the browser) is stripped out, using the appearance CSS property, before adding its pseudo element with the menu icon so that the user doesn’t see the square of the checkbox.

First, the basic markup:

<input type="checkbox">  <div id="menu">   <!--menu options--> </div> <div id="page">   <!--main content--> </div>

…and the baseline CSS for the Checkbox Hack and menu icon:

/* Hide checkbox and reset styles */ input[type="checkbox"] {   appearance: initial; /* removes the square box */   border: 0; margin: 0; outline: none; /* removes default margin, border and outline */   width: 30px; height: 30px; /* sets the menu icon dimensions */   z-index: 1;  /* makes sure it stacks on top */ }  
 /* Menu icon */ input::after {   content: "55";   display: block;    font: 25pt/30px "georgia";    text-indent: 10px;   width: 100%; height: 100%; }  
 /* Page content container */ #page {   background: url("earbuds.jpg") #ebebeb center/cover;   width: 100%; height: 100%; }

I threw in the styles for the #page content as well, which is going to be a full size background image.

The transition

Two things happen when the menu control is clicked. First, the menu icon changes to an × mark, symbolizing that it can be clicked to close the menu. So, we select the ::after pseudo element of checkbox input when the input is in a :checked state:

input:checked::after {   content: "d7"; /* changes to × mark */   color: #ebebeb; }

Second, the main content (our “earbuds” image) transforms, revealing the menu underneath. It moves to the right, rotates and scales down, and its left side corners get angular. This is to give the appearance of the content getting pushed back, like a door that swings open. 

input:checked ~ #page {    clip-path: polygon(0 8%, 100% 0, 100% 100%, 0 92%);   transform: translateX(40%) rotateY(10deg) scale(0.8);    transform-origin: right center;    transition: all .3s linear; } 

I used clip-path to change the corners of the image.

Since we’re applying a transition on the transformations, we need an initial clip-path value on the #page so there’s something to transition from. We’ll also drop a transition on #page while we’re at it because that will allow it to close as smoothly as it opens.

#page {   background: url("earbuds.jpeg") #ebebeb center/cover;    clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);   transition: all .3s linear;   width: 100%; height: 100%; }

We’re basically done with the core design and code. When the checkbox is unchecked (by clicking the × mark) the transformation on the earbud image will automatically be undone and it’ll be brought back to the front and centre. 

A sprinkle of JavaScript

Even though we have what we’re looking for, there’s still one more thing that would give this a nice boost in the UX department: close the menu when clicking (or tapping) the #page element. That way, the user doesn’t need to look for or even use the × mark to get back to the content.

Since this is merely an additional way to hide the menu, we can use JavaScript. And if JavaScript is disabled for some reason? No big deal. It’s just an enhancement that doesn’t prevent the menu from working without it.

document.querySelector("#page").addEventListener('click', (e, checkbox = document.querySelector('input')) => {    if (checkbox.checked) { checkbox.checked = false; e.stopPropagation(); } });

What this three-liner does is add a click event handler over the #page element that un-checks the checkbox if the checkbox is in a :checked state, which closes the menu.

We’ve been looking at a demo made for a vertical/portrait design, but works just as well at larger landscape screen sizes, depending on the content we’re working with.

This is just one approach or take on the typical fly-out menu. Animation opens up lots of possibilities and there are probably dozens of other ideas you might have in mind. In fact, I’d love to hear (or better yet, see) them, so please share!

The post Menu Reveal By Page Rotate Animation appeared first on CSS-Tricks.

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


, , , ,

Slide an Image to Reveal Text with CSS Animations

I want to take a closer look at the CSS animation property and walk through an effect that I used on my own portfolio website: making text appear from behind a moving object. Here’s an isolated example if you’d like to see the final product.

Here’s what we’re going to work with:

See the Pen
Revealing Text Animation Part 4 – Responsive
by Jesper Ekstrom (@jesper-ekstrom)
on CodePen.

Even if you’re not all that interested in the effect itself, this will be an excellent exercise to expand your CSS knowledge and begin creating unique animations of your own. In my case, digging deep into animation helped me grow more confident in my CSS abilities and increased my creativity, which got me more interested in front-end development as a whole.

Ready? Set. Let’s go!

Step 1: Markup the main elements

Before we start with the animations, let’s create a parent container that covers the full viewport. Inside it, we’re adding the text and the image, each in a separate div so it’s easier to customize them later on. The HMTL markup will look like this:

<!-- The parent container --> <div class="container">    <!-- The div containing the image -->   <div class="image-container">   <img src="https://jesperekstrom.com/wp-content/uploads/2018/11/Wordpress-folder-purple.png" alt="wordpress-folder-icon">   </div>   <!-- The div containing the text that's revealed -->   <div class="text-container">     <h1>Animation</h1>   </div> </div>

We are going to use this trusty transform trick to make the divs center both vertically and horizontally with a position: absolute; inside our parent container, and since we want the image to display in front of the text, we’re adding a higher z-index value to it.

/* The parent container taking up the full viewport */ .container {   width: 100%;   height: 100vh;   display: block;   position: relative;   overflow: hidden; }  /* The div that contains the image  */ /* Centering trick: https://css-tricks.com/centering-percentage-widthheight-elements/ */ .image-container {   position: absolute;   top: 50%;   left: 50%;   transform: translate(-50%,-50%);   z-index: 2; /* Makes sure this is on top */ }  /* The image inside the first div */ .image-container img {   -webkit-filter: drop-shadow(-4px 5px 5px rgba(0,0,0,0.6));   filter: drop-shadow(-4px 5px 5px rgba(0,0,0,0.6));   height: 200px; }  /* The div that holds the text that will be revealed */ /* Same centering trick */ .text-container {   position: absolute;   top: 50%;   left: 50%;   transform: translate(-50%,-50%);   z-index: 1; /* Places this below the image container */   margin-left: -100px; }

We’re leaving vendor prefixes out the code examples throughout this post, but they should definitely be considered if using this in production environment.

Here’s what that gives us so far, which is basically our two elements stacked one on top of the other.

See the Pen
Revealing Text Animation Part 1 – Mail Elements
by Jesper Ekstrom (@jesper-ekstrom)
on CodePen.

Step 2: Hide the text behind a block

To make our text start displaying from left to right, we need to add another div inside our .text-container:

<!-- ... -->    <!-- The div containing the text that's revealed -->   <div class="text-container">     <h1>Animation</h1>     <div class="fading-effect"></div>   </div>    <!-- ... -->

…and add these CSS properties and values to it:

.fading-effect {   position: absolute;   top: 0;   bottom: 0;   right: 0;   width: 100%;   background: white; }

As you can see, the text is hiding behind this block now, which has a white background color to blend in with our parent container.

If we try changing the width of the block, the text starts to appear. Go ahead and try playing with it in the Pen:

See the Pen
Revealing Text Animation Part 2 – Hiding Block
by Jesper Ekstrom (@jesper-ekstrom)
on CodePen.

There is another way of making this effect without adding an extra block with a background over it. I will cover that method later in the article. 🙂

Step 3: Define the animation keyframes

We are now ready for the fun stuff! To start animating our objects, we’re going to make use of the animation property and its @keyframes function. Let’s start by creating two different @keyframes, one for the image and one for the text, which will end up looking like this:

/* Slides the image from left (-250px) to right (150px) */ @keyframes image-slide {   0% { transform: translateX(-250px) scale(0); }   60% { transform: translateX(-250px) scale(1); }   90% { transform: translateX(150px) scale(1); }   100% { transform: translateX(150px) scale(1); }   }  /* Slides the text by shrinking the width of the object from full (100%) to nada (0%) */ @keyframes text-slide {   0% { width: 100%; }   60% { width: 100%; }   75%{ width: 0; }   100% { width: 0; } }

I prefer to add all @keyframes on the top of my CSS file for a better file structure, but it’s just a preference.

The reason why the @keyframes only use a small portion of their percent value (mostly from 60-100%) is that I have chosen to animate both objects over the same duration instead of adding an animation-delay to the class it’s applied to. That’s just my preference. If you choose to do the same, keep in mind to always have a value set for 0% and 100%; otherwise the animation can start looping backward or other weird interactions will pop up.

To enable the @keyframes to our classes, we’ll call the animation name on the CSS property animation. So, for example, adding the image-slide animation to the image element, we’d do this:

.image-container img {   /* [animation name] [animation duration] [animation transition function] */   animation: image-slide 4s cubic-bezier(.5,.5,0,1); }

The name of the @keyframes works the same as creating a class. In other words the name doesn’t really matter as long as it’s called the same on the element where it’s applied.

If that cubic-bezier part causes head scratching, then check out this post by Michelle Barker. She covers the topic in depth. For the purposes of this demo, though, it’s suffice to say that it is a way to create a custom animation curve for how the object moves from start to finish. The site cubic-bezier.com is a great place to generate those values without all the guesswork.

We talked a bit about wanting to avoid a looping animation. We can force the object to stay put once the animation reaches 100% with the animation-fill-mode sub-property:

.image-container img {   animation: image-slide 4s cubic-bezier(.5,.5,0,1);   animation-fill-mode: forwards; }

So far, so good!

See the Pen
Revealing Text Animation Part 3 – @keyframes
by Jesper Ekstrom (@jesper-ekstrom)
on CodePen.

Step 4: Code for responsiveness

Since the animations are based on fixed (pixels) sizing, playing the viewport width will cause the elements to shift out of place, which is a bad thing when we’re trying to hide and reveal elements based on their location. We could create multiple animations on different media queries to handle it (that’s what I did at first), but it’s no fun managing several animations at once. Instead, we can use the same animation and change its properties at specific breakpoints.

For example:

@keyframes image-slide {   0% { transform: translatex(-250px) scale(0); }   60% { transform: translatex(-250px) scale(1); }   90% { transform: translatex(150px) scale(1); }   100% { transform: translatex(150px) scale(1); } }  /* Changes animation values for viewports up to 1000px wide */ @media screen and (max-width: 1000px) {   @keyframes image-slide {     0% { transform: translatex(-150px) scale(0); }     60% { transform: translatex(-150px) scale(1); }     90% { transform: translatex(120px) scale(1); }     100% { transform: translatex(120px) scale(1); }   } }

Here we are, all responsive!

See the Pen
Revealing Text Animation Part 4 – Responsive
by Jesper Ekstrom (@jesper-ekstrom)
on CodePen.

Alternative method: Text animation without colored background

I promised earlier that I’d show a different method for the fade effect, so let’s touch on that.

Instead of using creating a whole new div — <div class="fading-effect"> — we can use a little color trickery to clip the text and blend it into the background:

.text-container {   background: black;   -webkit-background-clip: text;   -webkit-text-fill-color: transparent; }

This makes the text transparent which allows the background color behind it to bleed in and effectively hide it. And, since this is a background, we can change the background width and see how the text gets cut by the width it’s given. This also makes it possible to add linear gradient colors to the text or even a background image display inside it.

The reason I didn’t go this route in the demo is because it isn’t compatible with Internet Explorer (note those -webkit vendor prefixes). The method we covered in the actual demo makes it possible to switch out the text for another image or any other object.

Pretty neat little animation, right? It’s relatively subtle and acts as a nice enhancement to UI elements. For example, I could see it used to reveal explanatory text or even photo captions. Or, a little JavaScript could be used to fire the animation on click or scroll position to make things a little more interactive.

Have questions about how any of it works? See something that could make it better? Let me know in the comments!

The post Slide an Image to Reveal Text with CSS Animations appeared first on CSS-Tricks.


, , , ,