Skip to content

Instantly share code, notes, and snippets.

@CodeMyUI
Created August 23, 2016 00:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CodeMyUI/248a41701e839dd6476fa8f2e7ffa5b2 to your computer and use it in GitHub Desktop.
Save CodeMyUI/248a41701e839dd6476fa8f2e7ffa5b2 to your computer and use it in GitHub Desktop.
Perspective Scrolling in CSS / Portfolio Demo
<section class="wrap-3d">
<div class="item-3d">
<span class="ground"></span>
<figure class="item-content group">
<div class="item-img">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/46992/aw-white.png" alt="" />
</div>
<figcaption class="item-caption">
<p>
<strong>38mm and 42mm Case</strong><br>
7000 Series Silver Aluminum<br>
Ion-X Glass<br>
Retina Display<br>
Composite Back
</p>
<p>
<strong>Sport Band</strong><br>
White Fluoroelastomer<br>
Stainless Steel Pin
</p>
<p>
<a href="#">View 38mm in the store</a><br>
<a href="#">View 42mm in the store</a>
</p>
</figcaption>
</figure>
</div>
<div class="item-3d">
<span class="ground"></span>
<figure class="item-content group">
<div class="item-img">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/46992/aw-blue.png" alt="" />
</div>
<figcaption class="item-caption">
<p>
<strong>38mm and 42mm Case</strong><br>
7000 Series Silver Aluminum<br>
Ion-X Glass<br>
Retina Display<br>
Composite Back
</p>
<p>
<strong>Sport Band</strong><br>
Blue Fluoroelastomer<br>
Stainless Steel Pin
</p>
<p>
<a href="#">View 38mm in the store</a><br>
<a href="#">View 42mm in the store</a>
</p>
</figcaption>
</figure>
</div>
<div class="item-3d">
<span class="ground"></span>
<figure class="item-content group">
<div class="item-img">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/46992/aw-green.png" alt="" />
</div>
<figcaption class="item-caption">
<p>
<strong>38mm and 42mm Case</strong><br>
7000 Series Silver Aluminum<br>
Ion-X Glass<br>
Retina Display<br>
Composite Back
</p>
<p>
<strong>Sport Band</strong><br>
Green Fluoroelastomer<br>
Stainless Steel Pin
</p>
<p>
<a href="#">View 38mm in the store</a><br>
<a href="#">View 42mm in the store</a>
</p>
</figcaption>
</figure>
</div>
<div class="item-3d">
<span class="ground"></span>
<figure class="item-content group">
<div class="item-img">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/46992/aw-red.png" alt="" />
</div>
<figcaption class="item-caption">
<p>
<strong>38mm and 42mm Case</strong><br>
7000 Series Silver Aluminum<br>
Ion-X Glass<br>
Retina Display<br>
Composite Back
</p>
<p>
<strong>Sport Band</strong><br>
Pink Fluoroelastomer<br>
Stainless Steel Pin
</p>
<p>
<a href="#">View 38mm in the store</a><br>
<a href="#">View 42mm in the store</a>
</p>
</figcaption>
</figure>
</div>
<div class="item-3d">
<span class="ground"></span>
<figure class="item-content group">
<div class="item-img">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/46992/aw-black.png" alt="" />
</div>
<figcaption class="item-caption">
<p>
<strong>38mm and 42mm Case</strong><br>
7000 Series Silver Aluminum<br>
Ion-X Glass<br>
Retina Display<br>
Composite Back
</p>
<p>
<strong>Sport Band</strong><br>
Black Fluoroelastomer<br>
Stainless Steel Pin
</p>
<p>
<a href="#">View 38mm in the store</a><br>
<a href="#">View 42mm in the store</a>
</p>
</figcaption>
</figure>
</div>
<footer class="footer">
<p>A concept for perspective scrolling in CSS by <a href="http://codepen.io/Hornebom/" target="_blank">Hornebom</a></p>
<p>You can dig the source code <a href="http://codepen.io/Hornebom/pen/zGKVva">here</a></p>
</footer>
</section>

Perspective Scrolling in CSS / Portfolio Demo

A 3 dimensional scrolling experience built in CSS only. The trick is to rotate a single element around its x-axis, while its parent provides the perspective environment and a special perspective-origin.

Best viewed in Chrome/Safari on your desktop. Passed my test on Android, but lacks performance. Test failed on IOS7.

A Pen by Hornebom on CodePen.

License.

// =========================
// colors
// =========================
$master-grey: #f0f0f0;
// 3 shades of grey
$master-l-10: mix(white, $master-grey, 10%);
$master-d-10: mix(black, $master-grey, 10%);
$master-d-15: mix(black, $master-grey, 15%);
// font colors
$font-base: mix(black, $master-grey, 50%);
$font-dark: mix(black, $master-grey, 80%);
$font-spot: #08c;
// =========================
// one breakpoint is enough for this demo
// =========================
$wide-m:600px;
@mixin wide-m {
@media (max-width: #{$wide-m}) {
@content;
}
}
// @include wide-m {};
// =========================
// max-width for centered boxes
// =========================
$mx-width: 50rem;
// =========================
// reset and styling stuff
// =========================
*, *:before, *:after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.group:after {
content: "";
display: table;
clear: both;
}
html, body {
width: 100%;
height: 100%;
}
body {
font-family: "Myriad Pro", sans-serif;
font-size: 100%;
line-height: 1.5;
color: $font-base;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@include wide-m { font-size: 70%; }
}
a {
text-decoration: none;
color: $font-spot;
}
strong {
font-weight: normal;
color: $font-dark;
}
// =========================
// this wraps all items
// =========================
.wrap-3d {
width:100%;
height: 100%;
max-height: 100%;
padding-top: 5%;
overflow-x: hidden;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
background-color: $master-grey;
transform-style: preserve-3d;
perspective: 150rem;
perspective-origin: 50% 110%;
}
// =========================
// this wraps one single item
// =========================
.item-3d {
width: 100%;
margin-bottom: 20%;
padding-top: 10%;
padding-bottom: 5%;
transform-origin: 50% 100%;
transform-style: preserve-3d;
//box-shadow: inset 0 0 0 1px red;
@include wide-m { margin-bottom: 40%; }
}
// =========================
// this fakes the 3d surface
// has to be wider than it's parent
// =========================
.ground {
position:absolute;
top: 0;
right: -50%;
bottom: 0;
left: -50%;
width: 200%;
margin: 0 auto;
background-image:linear-gradient($master-d-10, $master-l-10 60%);
background-size: 100%;
transform-origin: 50% 100%;
transform: rotateX(70deg);
transform-style: preserve-3d;
backface-visibility: hidden;
//box-shadow: inset 0 0 0 10px black;
&:before, &:after {
content:'';
position: absolute;
width: 100%;
}
// this contains a radial-gradient, which fakes the watch's dropshadow
&:before {
top: 0;
left: 50%;
height: 100%;
width: 50%;
max-width: $mx-width;
background-image:radial-gradient($master-d-15, rgba($master-d-15,0) 60%);
background-size: 50% 80%;
background-repeat: no-repeat;
transform: translateX(-50%);
//box-shadow: inset 0 0 0 5px purple;
}
// the front-side
&:after {
bottom: -500px;
left: 0;
height: 500px;
background-image: linear-gradient($master-d-10, $master-l-10);
transform-origin: 50% 0;
transform: rotateX(-70deg);
//box-shadow: inset 0 0 0 5px blue;
}
}
//switching the dropshadows from left to right
.item-3d:nth-child(even) .ground:before {
background-position: 100% 50%;
animation: floating-shadow-r 5s -1s infinite;
}
.item-3d:nth-child(odd) .ground:before {
background-position: 0 50%;
animation: floating-shadow-l 5s -1s infinite;
}
// animations for the shadows
@keyframes floating-shadow-l {
0%, 100% {
background-size: 35% 80%;
background-position: 10% 80%;
}
50% {
background-size: 50% 80%;
background-position: 0 80%;
}
}
@keyframes floating-shadow-r {
0%, 100% {
background-size: 35% 80%;
background-position: 90% 80%;
}
50% {
background-size: 50% 80%;
background-position: 100% 80%;
}
}
// =========================
// a figure element that wraps
// the image and the caption
// =========================
.item-content {
position:relative;
width: 100%;
max-width: $mx-width;
margin: 0 auto;
display: flex;
align-items: center;
transform: translateZ(0); // fixes the layers in Safari
//box-shadow: inset 0 0 0 1px green;
}
// =========================
// additional wrap for the image
// =========================
.item-img {
position:relative;
float: left;
display: block;
width: 50%;
transform-origin: 50% 50%;
transform-style: preserve-3d;
animation: floating 5s -1s infinite;
//box-shadow: inset 0 0 0 1px red;
img {
display: block;
width: 100%;
height: auto;
transform-origin: 50% 100%;
transform: translateZ(-5rem);
}
}
.item-3d:nth-child(even) .item-img {
float: right;
order: 1;
}
// animation for the image
@keyframes floating {
0%, 100% { transform: translateY(-5%); }
50% { transform: translateY(0); }
}
// =========================
// the caption
// =========================
.item-caption {
display: block;
position: relative;
float: left;
width: 50%;
//box-shadow: inset 0 0 0 1px red;
}
.item-3d:nth-child(odd) .item-caption {
padding-left: 10%;
@include wide-m { padding-left: 5%; }
}
.item-3d:nth-child(even) .item-caption {
text-align: right;
padding-right: 10%;
@include wide-m { padding-right: 5%; }
}
.item-caption p {
font-size: 87.5%;
line-height: 1.333;
margin-bottom: 1.25rem;
@include wide-m { margin-bottom: 0.5rem; }
}
.item-caption p a {
position: relative;
display: inline-block;
margin-bottom: 0.3rem;
&:before {
content: '';
position: absolute;
right: 1rem;
bottom: 3px;
left: 0;
height: 1px;
background-color: $font-spot;
opacity: 0;
transition: opacity 0.25s;
}
&:after {
content: '\003E';
padding-left: 0.5rem;
text-decoration: none;
}
&:hover:before, &:active:before, &:focus:before {
opacity: 0.5;
}
}
// =========================
// the intro
// =========================
.intro {
position: relative;
width: 100%;
max-width: $mx-width;
margin: 0 auto;
padding: 15% 2rem;
text-align: center;
&:after {
content: '\2193';
position: absolute;
bottom: 20%;
left: 0;
width: 100%;
font-size: 150%;
animation: scroll-arrw 1s -1s infinite linear;
}
}
@keyframes scroll-arrw {
0% { transform: translateY(0); opacity: 0; }
50% { transform: translateY(80%); opacity: 1; }
100% { transform: translateY(160%); opacity: 0; }
}
.intro h1 {
font-size: 250%;
font-weight: normal;
color: $font-dark;
}
.intro p {
margin-bottom: 2rem;
font-size: 175%;
line-height: 1.4286;
}
// =========================
// the footer
// =========================
.footer {
padding: 0 2rem 20% 2rem;
text-align: center;
transform: translateZ(0);
a {
display: inline-block;
position: relative;
color: $font-dark;
&:before {
content: '';
position: absolute;
right: 0;
bottom: 3px;
left: 0;
height: 1px;
background-color: $font-dark;
opacity: 0;
transition: opacity 0.25s;
}
&:hover:before, &:active:before, &:focus:before {
opacity: 0.5;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment