Project 3 – Solar System

In this project, we are going to create a tool that presents our solar system.

The system is constructed by HTML DOM elements and CSS transform and transition.

Why is this project awesome?

By following the project steps, you will learn how to scroll the view in a parallax effect. This effect created an illusion of depth. That’s based on our real world that’s in perspective view. Things aren’t look the same at different distances. Things that’s far away from us looks smaller and moves slower to us. By creating the same scaling and movement at different layers, we can create similar depth feeling.

Preparation

Before we get started, we want to include one more Gulp plugin.

If you are using an existing project example, you may run the following command to add the gulp-sass compiler to the project.

1 npm install gulp-sass --save-dev

If you are working on a new folder, you may download the following skeleton which contains the basic project file structure and the package.json file.

1 http://mak.la/cjs-skeleton

Make sure to run npm install --save-dev after you download the skeleton code.

SCSS is a kind of CSS preprocessor. Preprocessor means that we write another syntax to express our css rules and then compile it into css. The beauty of Scss is that it is like css. If you don’t use any of the Scss specific syntax, the code is actually valid css file.

HTML

This is the HTML skeleton.

 1 <div id='app'> 
 2   <div id='solar-system' class='focus-earth'>
 3     <div class='layer deep-bg'></div>
 4     <div class='layer bg'></div>
 5     <div class='layer planets'>
 6       <!-- each planet here -->
 7     </div>
 8   </div>
 9   <div class='info-panel'>
10     <!-- Info text here -->
11   </div>
12   <div class='buttons'>      
13     <!-- button to focus on for every planet -->
14   </div>
15 
16   <div class='detail-panel out'>
17     <!-- pop up panel with detail information on every planet -->
18   </div>
19 </div>

Almost the elements are position absolute. The #app element is relative position to act as the relative coordinate for all the absolute position child elements. They all overlap together. Then we adjust the transform and too left bottom right to control their position.

The solar system had three layers. The deep background, background and the planets. The two background layers is essential to create a space movement illusion.

Basic CSS:

 1 * {
 2   box-sizing: border-box;
 3 }
 4 
 5 body, div, ul, li, h1, h2, h3, p {
 6   margin: 0;
 7   padding: 0;
 8 }
 9 
10 img {
11   max-width: 100%;
12 }
13 
14 html, body, #app, #solar-system {
15   width: 100%;
16   height: 100%;
17 }
18 
19 
20 #app {
21   position: relative;  
22   overflow: hidden;
23 }

Planet buttons

HTML:

 1 <div class='buttons'>
 2     <a href='#mercury' class='focus-button'>Mercury</a>
 3     <a href='#venus' class='focus-button'>Venus</a>
 4     <a href='#earth' class='focus-button'>Earth</a>
 5     <a href='#mars' class='focus-button'>Mars</a>
 6     <a href='#jupiter' class='focus-button'>Jupiter</a>
 7     <a href='#saturn' class='focus-button'>Saturn</a>
 8     <a href='#uranus' class='focus-button'>Uranus</a>
 9     <a href='#neptune' class='focus-button'>Neptune</a>
10   </div>

CSS:

 1 /* User Inteface */
 2 .buttons {
 3   position: absolute;
 4   height: 100%;
 5   right: 0;
 6 
 7   display: flex;
 8   flex-direction: column-reverse;
 9 
10   a {
11     display: block;
12     flex: 1;
13 
14     text-decoration: none;
15     color: #555;
16 
17     line-height: 50px;
18 
19     &.active {
20       color: white;
21     }
22   }
23 }

The button is laid out using the flexbox to ensure they are evenly distributed.

The nested scope in the preprocessor allows us to group related styles together. We can modularize the styles to specific part of the app.

The solar system

 1 $space-height: 13000px;
 2 $bg-z: 10;
 3 $deep-bg-z: 30;
 4 
 5 #solar-system {    
 6   position: absolute;
 7   overflow: hidden;  
 8   transform-origin: 0 0;
 9 }
10 
11 
12 .layer {
13   position: absolute;
14   transition: all 1.5s ease-out;
15 }
16 
17 .deep-bg {
18   width: 100%;
19   height: $space-height;
20   background: black url(../images/deep-bg.jpg);
21 }
22 
23 .bg {
24   width: 100%;
25   height: $space-height;
26   background: url(../images/bg.jpg);
27   opacity: .3;
28 }
29 
30 .planet {
31   position: absolute;   
32   img {
33     max-width: 80px;  
34   }
35 }

Those preprocessors usually allow us to define variable and expressions. For example, we defined several variables for our solar system. They are the height of the space view. The virtual Z index of the layers.

We don’t need the height of the space view if we order the planets from top to bottom.

We need the height because we are calculating the position from the bottom.

Showing the planets

The value of the planet is based on the average distance the real planet are away from the sun. We have a multiplier to adjust the scale.

 1 $planets: "mercury" "venus" "earth" "mars" "jupiter" "saturn" "uranus" "neptune";
 2 $distances:  57*2px 108*2px 150*2px 228*2px 779*2px 1430*2px 2880*2px 4500*2px;  
 3 $x-positions: 30vw 15vw 45vw 50vw 35vw 60vw 25vw 56vw;
 4 
 5 @for $i from 1 through length($planets) {
 6   $name: nth($planets, $i);
 7   $distance: nth($distances, $i);
 8   $x-position: nth($x-positions, $i);
 9   .#{$name} {
10     transform: translateX($x-position) translateY(calc(#{$space-height} - #{$dis\
11 tance}));  
12   }
13 
14   ...
15 }

The looping expressions allows us to define similar css rules without explicitly typing all of them. For example, we use loop and a list to iterate all 8 planets rules and their styles when focused.

Scss list is useful when we cant express the calculation with just the looping index. For example, we want to iterate the name of the 8 planets, so we use a list to store the planet name and use it to define the class based on these names.

You may think that list is kind of array in programing language. Actually Scss even has a nested list like a 2 dimension array.

There are some utility functions to help us manipulate the scss list. The most common one is the nth function where we get the value based on the index, usually within an for loop. The length function helps us to define the ending condition if the for loop.

The calc function in css allows is to express a calculation as a property value.

 1 @for $i from 1 through length($planets) {
 2   $name: nth($planets, $i);
 3   $distance: nth($distances, $i);
 4 
 5   ...
 6 
 7   #solar-system.focus-#{$name} {
 8     .planets.layer {
 9       transform: translateY(calc(-#{$space-height} + #{$distance} + 40vh));    
10     }
11     .bg.layer{
12       transform: translateY(calc((-#{$space-height} + #{$distance} + 40vh) / #{$\
13 bg-z}));
14     }
15     .deep-bg.layer{
16       transform: translateY(calc((-#{$space-height} + #{$distance} + 40vh) / #{$\
17 deep-bg-z}));
18     }
19   }
20 }

The focus style explicitly moves the 3 layers into different transform Y based on the calculation.

By toggling different focus styles on different planets, the 3 layers move in different speeds and thus created the parallax effect.

Detail Panel

1 <div class='detail-panel out'>
2   <div id='tab-mercury' class='tab'>          
3     <h1>Mercury</h1>
4     <img src='images/mercury.jpg' alt='Mercury'>
5     <p><small>Photo by NASA. Public Domain.</small></p>
6     <p><small>Tap anywhere to close</small></p>
7   </div>
8   <!-- other planets detail go here -->
9 </div>