PK Creative Spring Festival, I am participating in the “Spring Festival Creative Submission contest”, please see:Spring Festival creative Submission contest

introduce

A single shot in a web page usually refers to a way of showing different picture elements successively in front of the audience by imitating the stretching of the lens in the page. It is called “one-shot to the end” because its rendering effect is very similar to the one-shot to the end in film and television.

Spring Festival is coming, we will use SVG + JS to make a one-shot web special effect in this issue, and wait for our New Year’s Eve.

Of course, let’s first come to kangkang effect:

The body of the

1. The HTML structure

<div id="app">
    <h1>
        <div>
            <p>From New Year's eve</p>
            <p>There are<span id="day">0</span>day</p>
        </div>
    </h1> 

    <div class="tiger">
        <svg class="tiger-icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2653"
            width="32" height="32">
            <! -- Copy path -->
            <! --<path class="tiger-mask" d="..." ></path>-->
            <! -- Copy path -->
        </svg>
    </div>

    <video src="./assets/video.a1577323.mp4" loop autoplay muted playsinline></video>

    <h2>
        <div>
            <p></p>
            <p></p>
            <p></p>
            <p></p>
        </div>
    </h2>
</div>
Copy the code

Here we expect to do four full-screen scenes:

  • Scene 1: prompt the number of days before New Year’s Eve, if the New Year’s eve we will change in JS to other words, do not show the number of days.

  • Scenario 2: Find an SVG tiger icon and copy the code into it because the path is too long and it is commented here.

  • Scene 3: To find a cheerless video to put in, make sure to reduce the importance of the four attributes, loop Autoplay muted playsinline, to a muted environment.

  • Scene 4: We can see that there are four empty P tags, and in fact, there will be four random greetings at the end, which will be seen in the JS logic behind the content.

2. CSS styles

html.body {
    width: 100%;
    height: 6666px;
    position: relative;
}

#app {
    width: 100%;
    position: sticky;
    top: 0;
    width: 100%;
    height: 100vh;
    overflow: hidden;
}

video {
    width: 100%;
    height: 100%;
    position: absolute;
    object-fit: cover;
    left: 0;
    top: 0;
}

.tiger {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 20vh;
    height: 20vh;
    min-width: 20vh;
    min-height: 20vh;
    box-shadow: 0px 0px 0px 100vw rgb(170.0.0), 0px 0px 0px 50px rgb(170.0.0) inset;
    z-index: 10;
    background-color: rgb(170.0.0);

}

.tiger.transparent {
    background-color: transparent;
}

.tiger-icon {
    position: absolute;
    width: 100%;
    height: 100%;
    opacity: 0;
}

.tiger-line..tiger-mask {
    fill: rgb(247.191.39)}h1.h2 {
    position: absolute;
    width: 100%;
    height: 100vh;
    font-size: 11vh;
    color: rgb(247.191.39);
    position: absolute;
    font-family: 'fangsong', Arial, sans-serif;
    font-weight: bold;
    letter-spacing: 1vh;
    line-height: 20vh;
    top: 0;
    left: 0;
    z-index: 99;
    display: flex;
    align-items: center;
    justify-content: center;
    text-shadow: 2px 1px 15px rgb(247.191.39);
}

h1>div.h2>div {
    text-align: center;
}

h2 {
    background-image: repeating-radial-gradient(circle at center center, transparent 0px, transparent 8px.rgba(255.255.255.0.05) 8px.rgba(255.255.255.0.05) 11px, transparent 11px, transparent 17px.rgba(255.255.255.0.05) 17px.rgba(255.255.255.0.05) 25px, transparent 25px, transparent 38px.rgba(255.255.255.0.05) 38px.rgba(255.255.255.0.05) 42px),
        repeating-radial-gradient(circle at center center, rgb(170.0.0) 0px.rgb(170.0.0) 11px.rgb(170.0.0) 11px.rgb(170.0.0) 19px.rgb(170.0.0) 19px.rgb(170.0.0) 24px.rgb(170.0.0) 24px.rgb(170.0.0) 33px.rgb(170.0.0) 33px.rgb(170.0.0) 44px.rgb(170.0.0) 44px.rgb(170.0.0) 46px);
    background-size: 60px 60px;
    opacity: 0;
    line-height: 15vh;
}

h2 p {
    height: 15vh;
    transition:.3s all;
}
Copy the code

The main points to note in CSS are:

  • I want to add a huge height for the body, so I wrote 6666px just for luck.
  • Div# app, we need to keep position: sticky at the top to make sure the scene always fits the screen.
  • The other four scenes are full screen.
  • Div. Tiger uses box-shadow to cover any gaps in the scene that leak out.

3. Basic logic

let wordList = [
    "Happy New Year, longevity, health, peace and prosperity."."All the money, all the fun, all the success."."Good fortune, good fortune, good dreams."."Congratulations on the Spring Festival and the new fortune."."Happy family, happy career, happy life."."All your wishes come true."."Good luck, good luck, good spring, good harvest."."Happy New Year, good school, good luck and all the best."."Happy New Year to you and yours."."All things return to spring, the sky is open, and people are in spring."
]

let $day = document.getElementById("day")
let $h1 = document.querySelector("h1")
let $h2 = document.querySelector("h2")
let $TigerSvg = document.querySelector(".tiger-icon")
let $Tiger = document.querySelector('.tiger')
let $TigerMask = document.querySelectorAll('.tiger-mask')
let $plist = $h2.querySelectorAll("p")
let word = "";
Copy the code

Let’s define these parameters first:

  • The wordList is the message to be displayed below, and one of the 10 strings is assigned to word to ensure that it is opened differently each time.
  • The rest is just to get the elements directly, so you don’t have to do this again and again.

Next, let’s initialize:

function init() {
    let now = new Date(a);let cx = new Date("2022-1-31");
    word = wordList[~~(Math.random() * wordList.length)].split("");
    $plist.forEach((p, i) = > p.innerText = word[i])
    if (now > cx) {
        $h1.querySelectorAll("p").forEach((p, i) = > p.innerText = ["Happy New Year".The Year of the Tiger][i])
        return;
    }
    let d = Math.max(0, ~~((cx - now) / 1000 / 86400));
    $day.innerText = d;
}
init()
Copy the code

In the initialization method, we calculated the time until New Year’s Eve, and randomly added the blessing language generated string to the interface.

With all the preparation done, how can you make it alternate between different scenarios? Notice, notice, here we go

window.addEventListener("scroll".e= > {
    let scrolled = document.documentElement.scrollTop / (document.documentElement.scrollHeight - document.documentElement.clientHeight)
})
Copy the code

We should monitor the scroll method and then calculate scrolled, which means that every time I scroll, I should calculate the ratio of the distance of my current scroll bar to the available height, so that the percentage of the current scrolling to the page can be obtained, in other words, the progress value. Later we will scroll to change the different properties of the scene content in real time according to this progress value to complete the effect of one shot to the end.

window.addEventListener("scroll".e= > {
    let scrolled = document.documentElement.scrollTop / (document.documentElement.scrollHeight - document.documentElement.clientHeight)
    $Tiger.style.width = $Tiger.style.height = document.documentElement.clientWidth * 36 * (scrolled * scrolled * scrolled) + 'px'
    if (scrolled <= 0.1) {
        $h1.style.opacity = (0.1 - scrolled) * 10
        $h1.style.marginTop = scrolled * 1000 * -1 + 'px'
    } else {
        $h1.style.opacity = 0
    }
    if (scrolled <= 0.2) {
        $TigerSvg.style.opacity = (scrolled - 0.1) * 10
    } else {
        $TigerSvg.style.opacity = 1
    }
    if (scrolled >= 0.36) {
        $TigerMask.forEach(n= > n.style.opacity = (1 - scrolled) * 1.5);
        $Tiger.classList.add('transparent')}else {
        $TigerMask.forEach(n= > n.style.opacity = 1);
        $Tiger.classList.remove('transparent')}if (scrolled >= 0.6) {
        let limit = ~~((scrolled - 0.75) * 100 / 5)
        $plist.forEach((p, i) = > {
            p.style.opacity = limit >= i ? 1 : 0;
            p.style.transform = limit >= i ? "scale(1)" : "scale(3)"
        })
        $h2.style.opacity = (scrolled - 0.5) * 2;
    }
    else {
        $plist.forEach((p, i) = > {
            p.style.opacity = 0;
            p.style.transform = "scale(3)"
        })
        $h2.style.opacity = 0; }})Copy the code

There is only so much to deal with the current business logic. It can be seen that we conduct different operations on the contents in different stages through scrolled progress value. Like constantly changing transparency, or marginTop, etc. I will not repeat them all here.

conclusion

In fact, we only wrote four scenes this time, because it is completed by pure JS, so the business volume is quite large. If we want to make a lot of effects later, we can also use gSAP to complete them with time line, which will save a lot of business processing and be more clear. In short, the core implementation is still very simple, is to calculate your current progress value, to constantly change the state, have the opportunity to try very fun.

Finally, I wish you all a prosperous year of the Tiger, and the coming year will be full of vigor and vitality.