Hello, I’m Steven.

In this episode, we’re going to replicate the effect of this card in the App Store:

I was going to just use HTML and CSS, but I ended up using JavaScript, so let’s get started.

This video version of the tutorial at www.bilibili.com/video/BV1bC… , welcome the attention of sanlian!

Part of the HTML

Open the CodePen editor and first create the HTML structure. I’m going to add a

, class is card, and I’m going to add a random image from the Unsplash site. Add THE title, text like APP OF THE DAY.

< content >

< content > Why you need two layers of

, we’ll see later.

Add text inside, generate some false words, and organize them with the

paragraph tag.

So the HTML structure is going to look something like this, and then the CSS part.

Part of the CSS

Added :root selector and set the base text size to 15px. Font-family: Helvetica.

Then define some variables. Since this effect works on the width of the phone, I will set the page width to 480px and define –body-width to be 480px. Then define the card size, –card-width = 420px, –card-height = 280px.

Redefine the height of the image. The height of the unexpanded image –img-height was defined as 226px, and the height of the expanded image — img-height-Expanded was defined as 320px. Finally, the background color is set to dark gray.

Add the body selector, set the width to var(–body-width), the background color to light gray, and margin to auto. This will center the body.

Set display to flex, Flex-direction to column, align-items to center, and min-height to 100vh. A little bit of padding on the top and bottom, 1rem 0.

Add the.card selector to var(–card-width), height to var(–card-height), and background color to white.

The white background cannot be seen temporarily, because the size of this picture is larger than that of the card container and it is completely covered. Add a.card img selector, set display to block, width to 100%, and height to var(–img-height), then add object-fit: The cover setting allows the image to be scaled and filled.

Go back to the Settings of.card, add rounded corners, and set border-radius to 1rem. Just a little bit of shade, a very light gray.

Then we will find that the upper left and upper right corner of the image do not have rounded corners, we can add overflow: hidden in.card, let. Card will cover the excessive part, make the image into rounded corners. However, since the rounded corners turn to right angles when opening.card, and overflow cannot be animated, I will not use overflow here. Instead, I will use rounded corners in the upper left and upper right corners in IMG.

Then set the style of the caption, add the. Card h4 selector, set margin to 0 and the text size to 1.5rem; Font is set to bold; Add the padding, up and down to 0.8rem, left and right to 1.2rem; Set the background color to white.

I want the text to be more centered vertically, set the line-height to 2rem, and make the spacing a little smaller, letter-spacing to -0.5px, and padding-bottom to 0 so that the rounded corners of the.card are not obscured.

Next is the part that sets the text, adding the.card.content-wrapper and.card.content-wrapper. Content selectors.

Why do we have.content-wrapper and.content? Since the height of the text container is calculated and set by JavaScript when the card is clicked to expand, we apply the expanded animation to the outer layer and the height to the inner layer.

This way, when you close the card, you don’t have to restore the height, but the point is to write less JavaScript and let CSS do it.

Set the.content style, add the padding, and set it to 0 up and 0 down, about 1.2rem; Set the background color to white; Then set overflow to auto so that the page can scroll when the text is higher than the height set by the container. The height of the container will be controlled later in JavaScript.

Add the.card p selector and set the text size to 1.2rem and the line height to 1.5rem.

Then go to the.content-Wrapper, set the height to 0, and add overflow: hidden, so that the parts beyond the container will be hidden.

Now that the cards are styled, copy a few more cards into the HTML before you start expanding. In order to display different random images, I will add different parameters to the URL of Unsplash, and then add 1, 2, 3 and 4.

Then go to the.card selector and add margin: 1rem 0 to separate the cards a bit.

Part of the JavaScript

Next, I’ll deal with the expansion of the card by adding a class to change the style of the card when it is clicked. In order to reduce the amount of JavaScript to write, I will add jQuery, open Settings, add jQuery in the JS section, and click Save & Close.

In the JavaScript part, add the.card on(‘click’) event. Define a variable, card assigns the value E. Cap, and what you get here is the.card that you clicked on.

Then add $(card).toggleclass (‘active’), so that if the card does not have an active class, it will be added, and sometimes it will be removed, so that the effect is expanded and folded.

CSS style adjustments

Now we can go back to the CSS part, and set the style for the card in the active state. Add four selectors:.card.active for moving card position,.card.active for h4 header style,.card.active img image style, and.card.active. Content-wrapper to expand text.

The first thing I want to do is expand the text. In the.content-Wrapper selector, add height: 100vh and click on the card.

You can see that the text has been successfully expanded, and now we’re going to move the card, but in addition to moving the card, we’re going to enlarge the card a little bit to fill the left and right width.

Insert transform into.card selector and set translateY() as translateY(). How much is translateY() moving up? In fact, you need to calculate the distance between the element and the top to keep it close to the top.

Then add scale() to enlarge the card a little bit. The scale is the body width divided by the card width, which is 480 divided by 420. The transform-Origin center is set to 50% 0.

Let’s start with some style tweaks. While unfolding, remove the rounded corners and remove the rounded corners from the image. Then pull the image higher:

Go back to the.card selector and add Transition:.3s all for cubic- Bezier (0, 1, 0.95, 1.05) :

You can open developer tools and see a linear diagram of this acceleration:

You can try to pull on this curve to get different acceleration effects, and I’ve set this up so that it will bounce back a little bit when it opens and retracts.

To calculate the displacement

Going back to the JavaScript part, we want to calculate the distance between the card and the top. Define the variable card_offset_scrollTop to subtract window.scrollTop() from the card offset().top, which is the scrolling distance. Then set the calculation result on the card in the form of CSS variable, change the variable name to –data-offset-top, set the value by -1 and add px units.

In the.card.active transform, translateY() is translateY(). Replace -300px with var(–data-offset-top) and click test:

You can navigate to the top of the page.

Continue to optimize

You think you’re done? Do not stop, continue to optimize the rest of the parts.

Now scroll the page after you have unrolled the card, so pause the body scroll after you have opened the card.

In the JavaScript section, add noscroll class to the body if the card has the active class, which means it is open. Otherwise, remove the noScroll class.

Open the CSS section, add the body. Noscroll selector, set overflow: hidden, so you can achieve the effect of preventing scroll.

In JavaScript, define the height variable and assign it to window.height(). To calculate the height of the text section, subtract the height of the image from the window height and then the height of the title.

Then apply this height to the.content container and test:

Why can’t roll to the end? So there’s something wrong with the height calculation, but what’s wrong with the calculation?

You have three seconds to think about it. Three, two, one.

This is because our card is enlarged by the scale() of the transform, so when calculating the height of the picture and the title, we need to multiply the magnification ratio.

Define a variable named ratio and assign the value 480/420. Multiply the height of the image and the height of the caption by the ratio. Finally, divide the total by the ratio again.

I got the height right this time.

With a few final twevers, you’ll notice that THE lower padding-bottom OF THE APP OF THE DAY is a little less as you scroll, so add padding-bottom:.8rem in.card.active H4:

Then, when the text appears, add a gradual effect, and set opacity:.8, transition:.3s inside the.content-Wrapper all ease-out:

Add opacity: 1, Transition:.3s all ease-in inside the unrolled.content-wrapper to create a different acceleration effect when it is opened and folded.

Let’s see how this case works

That’s all for this episode.


Source code for this case is at codepen. IO /stevenlei/p…

Your support is my motivation, please pay attention to CodingStartup at least, let’s work together!

  • B station: space.bilibili.com/451368848
  • YouTube: youtube.com/codingstart…
  • The Denver nuggets: juejin. Cn/user / 249773…