惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Security Blog
Microsoft Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
美团技术团队
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
G
Google Developers Blog
阮一峰的网络日志
阮一峰的网络日志
The Cloudflare Blog
J
Java Code Geeks
Martin Fowler
Martin Fowler
M
MIT News - Artificial intelligence
IT之家
IT之家
博客园 - 三生石上(FineUI控件)
月光博客
月光博客
Google DeepMind News
Google DeepMind News
小众软件
小众软件
V
V2EX
Hugging Face - Blog
Hugging Face - Blog
爱范儿
爱范儿
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Jina AI
Jina AI
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
腾讯CDC
B
Blog

CloudCannon Blog

Building with AI: Git-based vs headless vs traditional CMS CloudCannon + Astro: performance meets powerful content management Introducing the Astro Component Starter Introducing Jetstream — built on the Astro Component Starter Why we switched to the system font stack Redesigning CloudCannon’s docs with Diátaxis, Lume, and Pagefind Make content editing more visual: upgraded Editable Regions How Configuration Mode makes building editing interfaces easy Your hosting just got an upgrade (and a price cut) Custom testing domains for professional branding Keep your content consistent with input validation Managing multilingual content in CloudCannon Simplify team publishing with conflict resolution and domain tools Open Beta: Publishing Conflict Resolution Getting started with CloudCannon and Astro: Bookshop, components, and live editing Welcome to the CloudCannon Community! Omnichannel delivery is just marketing spin from API-based CMS companies Getting started with CloudCannon and Astro: Snippets and Collections Managing digital assets in CloudCannon: a guide to smart asset storage Understanding CloudCannon's branching workflows and Projects: a complete guide What is a static website? CloudCannon’s 2024 wrapped Getting started with CloudCannon and Astro: WYSIWYG blogging Jamstack vs. WordPress: reasons to make the change The top five static site generators for 2025 (and when to use them!) Free Jekyll themes for 2025: ten great community options Eleventy (11ty) vs. Hugo How to set up WYSIWYG editing with MkDocs Material The rise of static-first websites: why major brands are making the switch Watching your Core Web Vitals on Jamstack
How to create a super simple Christmas landing page
2014-12-23 · via CloudCannon Blog

This week I felt like doing something Christmas related, it seemed quite relevant. Instead of enjoying the summer sun that a New Zealand Christmas offers I decided to build an experimental landing page to share. Hope you enjoy it.

What is it? Direct link to this section

We wanted a neat way to send our users a present for the holiday season. The obvious way to give a present is in a box that they can open. Who opens presents in a 2D space? Maybe Mario but I don't think he's one of our users. Here is my Christmas Landing equipped with a 3D present fully animated.

Let's break it down.

The Layout Direct link to this section

The new version of Skeleton responsive boilerplate came out recently so I decided to use that. It gives a base which doesn't get in the way and it is basically a better browser default. This allows me to extend it really easily, pairing their grid system with our repeatable regions means I can set up the layout and hand it off. Check it out, I highly recommend it.

The Snow Background Direct link to this section

The Snow background adds a really nice effect. It uses a set of background images paired with CSS animations to make them move separately from one another. A full tutorial is available on designmodo.com.

@keyframes snow {
0% {
background-position: 0px 0px;
}
100% {
background-position: 500px 1000px, 400px 400px, 300px 300px;
}
}

body {
background-color: #eee;
background-image: url('snow.png'), url('snow2.png'), url('snow3.png');

animation: snow 20s linear infinite;
}

The Box Direct link to this section

The Box uses 3D transformations to align all the edges. I originally based the code off a tutorial found by googling "CSS Cube". It goes in depth about the 3D transformations. One very important attribute to note is transform-style: preserve-3d;, this tells the browser to act in a 3D space. If your transforms and transitions are looking very flat then this is probably what is missing. FYI, colours used are from the Google Material Design colour pallete.

<section class="cube-wrapper">
<div class="cube">
<figure class="front"></figure>
<figure class="back"></figure>
<figure class="right"></figure>
<figure class="left"></figure>
<figure class="top"></figure>
<figure class="bottom"></figure>
<figure class="shadow"></figure>
</div>
</section>

This box will live in two states, 'open' and 'closed'. I want the difference between the states to be a single class on the parent element. This way I can toggle between the states with just:

$(".cube-wrapper").click(function () {
$(this).toggleClass("open");
});

The closed state has 4 segments on the top all pointed inwards. This is just four divs occupying the four different quadrants of the parent square. I did it this way instead of adding more parent figures to keep things modular.

<figure class="top">
<div class="lower lower-left"></div>
<div class="lower lower-right"></div>
<div class="upper upper-left"></div>
<div class="upper upper-right"></div>
</figure>
.cube .top div {
width: 50%;
height: 100%;
position: absolute;

font-size: 60px;
transform-origin: left center;

border: 1px solid #3E2723;
box-sizing: border-box;
}

.cube .top .lower {
height: 50%;
width: 100%;
line-height: 96px;
}

.open .cube .top .lower {
z-index: 2;
}

.cube .top .upper-right {
transform-origin: right center;
transform: translateZ(0px) translateX(98px);
background: #795548;
}

.cube .top .lower-right {
transform-origin: bottom center;
transform: translateZ(-1px) translateY(98px);
background: #8D6E63;
}

.cube .top .upper-left {
transform-origin: left center;
transform: translateZ(0px);
background: #8D6E63;
}

.cube .top .lower-left {
transform-origin: top center;
transform: translateZ(-1px);
background: #795548;
}

This CSS places the 4 flaps in the correct position using transforms. The Z translations are very important here. The upper flaps need to be 1px above the others to prevent any overlapping effects. Another important part are the transform origins, these say where the animations should originate from.

For the open state we want the elements to flip across from the outside edge which is where we have set the transform origin.

.open .cube .top .upper-right {
transform: translateZ(-1px) translateX(98px) rotateY(150deg);
background: #795548;
}

.open .cube .top .lower-right {
transform: translateZ(-1px) translateY(98px) rotateX(-150deg);
background: #A1887F;
}

.open .cube .top .upper-left {
transform: translateZ(-1px) rotateY(-150deg);
background: #A1887F;
}

.open .cube .top .lower-left {
transform: translateZ(-1px) rotateX(150deg);
background: #795548;
}

We have translated the elements to be all on the same Z plane. I chose 150 degrees very intentionally, if it gets too close to 180 degrees the browser can't decide which way to rotate the flaps. The inverse rotation through the box didn't look that realistic so I decided to use 150 degrees.

A Shadow to top it all off Direct link to this section

Quite a simple effect gives the whole scene a lot more depth. I replicated the bottom edge of the box, extended it and changed the background.

.cube .shadow {
transform: rotateX(-90deg) translateZ(101px) translateX(0);
width: 355px;
background: rgba(0,0,0,0.1);
border: 0;
padding: 2px;
}

.open .cube .shadow {
transform: rotateX(-90deg) translateZ(101px) translateX(100px);
}

The Animations Direct link to this section

This is where a great looking box comes alive. Everything to this point has been built using transforms and a single class change. This means that all the hard work has been done and we can just roll over some CSS transitions.

First we want to add the transitions to the original state. This will allow us to synchronise the different parts when the box is closing.

.cube {
transition: transform 1s ease 0,
background 1s ease 0;
}

.cube .top div,
.cube .shadow
{
transition: transform 1s ease 1s,
background 1s ease 1s;
}

.cube .top .lower {
transition: transform 1s ease 0,
background 1s ease 0,
z-index 0 ease 0;
}

Second we want to add the transitions to the .open state. This will allow us to synchronise the different parts when the box is opening.

.open .cube {
transition: transform 1s ease 2s,
background 1s ease 2s;
}

.open .cube .top div,
.open .cube .shadow
{
transition: transform 1s ease 0s,
background 1s ease 0s;
}

.open .cube .top .lower {
transition: transform 1s ease 1s,
background 1s ease 1s,
z-index 0 ease 1s;
}

You can try these out by clicking any box on this page.

All Together Again Direct link to this section

Why would I ever use this? Direct link to this section

This shows just how much you can achieve with CSS; 3D transformations, animations and handy boilerplates lets you get a lot done in a very short amount of time. Also it's Christmas, and who doesn't like to give out presents.

That's it Direct link to this section

This landing page was a great afternoon project, plugging together a whole lot of different tutorials into a really useful resource. If you like it feel free to contribute to the GitHub Repository. I'd love to add some other branches with different holidays. If you have any questions or want to spread some cheer be sure to comment below. Merry Christmas.