<div class="house" id="house" data-rooms="6">
<div class="house-wings" data-flip-key="wings">
<div class="house-left-wing">
<div class="house-window"></div>
<div class="house-window"></div>
<div class="house-sparkle">
<div class="house-sparkle-dots"></div>
</div>
</div>
<div class="house-right-wing">
<div class="house-window"></div>
<div class="house-window"></div>
<div class="house-sparkle">
<div class="house-sparkle-dots"></div>
</div>
</div>
<div class="house-roof">
<div class="house-ledge"></div>
</div>
</div>
<div class="house-front" data-flip-key="front">
<div class="house-chimney"></div>
<div class="house-facade"></div>
<div class="house-window">
<div class="house-sparkle">
<div class="house-sparkle-dots"></div>
</div>
</div>
<div class="house-doorway">
<div class="house-stairs"></div>
<div class="house-door"></div>
</div>
<div class="house-gable">
<div class="house-roof">
<div class="house-ledge"></div>
</div>
</div>
</div>
</div>
<label class="house-label" for="range" id="label">Rooms</label>
<input type="range" min="3" max="6" step="1" value="6" id="range">
$color-primary: #224889;
$color-roof: #A6CFFF;
$color-ledge: #79AAFF;
$color-window-left: #65EBFF;
$color-window-right: #71FBFF;
$color-window: linear-gradient(to right, $color-window-left, $color-window-left 49.9%, $color-window-right 50%, $color-window-right);
$color-shadow: #E1EAFF;
$duration: 500ms;
$delay: 70ms;
$easing: cubic-bezier(.1, 0, .3, 1);
$parts: (
6: (
wings: 425px,
front: 150px,
),
5: (
wings: 355px,
front: 150px,
),
4: (
wings: 300px,
front: 125px,
),
3: (
wings: 240px,
front: 150px,
),
);
@each $rooms, $dimensions in $parts {
[data-rooms="#{$rooms}"] {
@each $part, $width in $dimensions {
.house-#{$part} {
width: $width;
left: calc(50% - #{$width / 2});
}
#{--#{$part}-width}: $width;
}
}
}
.house {
height: 225px;
width: 520px;
}
.house-label {
text-transform: uppercase;
font-weight: bold;
padding-left: calc(20px + 1ch);
font-size: 25px;
color: $color-primary;
margin: 30px 0 5px;
font-family: Arial Rounded MT Bold, Helvetica Neue, Helvetica, sans serif;
&:before, &:after {
position: absolute;
text-align: right;
left: 0;
top: 0;
padding: 0 .5ch;
will-change: transform;
}
&:before {
content: attr(data-prev-rooms);
}
&:after {
content: attr(data-rooms);
}
@for $i from 6 through 3 {
&[data-rooms="#{$i}"][data-rooms-delta^="-"] {
&:before {
animation: prev-label-up-#{$i} $duration $easing both;
}
&:after {
animation: label-up-#{$i} $duration * 2 $easing both;
}
}
&[data-rooms="#{$i}"]:not([data-rooms-delta^="-"]) {
&:before {
animation: prev-label-down-#{$i} $duration $delay $easing both;
}
&:after {
animation: label-down-#{$i} $duration * 2 $delay $easing both;
}
}
@keyframes prev-label-up-#{$i} {
from {
transform: translateY(0);
opacity: 1;
}
to {
transform: translateY(-100%) scale(1.5);
opacity: 0;
}
}
@keyframes prev-label-down-#{$i} {
from {
transform: translateY(0);
opacity: 1;
}
to {
transform: translateY(100%) scale(1.5);
opacity: 0;
}
}
@keyframes label-up-#{$i} {
from {
transform: translateY(100%);
opacity: 0;
}
50% {
transform: translateY(0) scale(1.5);
opacity: 1;
}
to {
transform: translateY(0);
opacity: 1;
}
}
@keyframes label-down-#{$i} {
from {
transform: translateY(-100%);
opacity: 0;
}
50% {
transform: translateY(0) scale(1.5);
opacity: 1;
}
to {
transform: translateY(0);
opacity: 1;
}
}
}
}
.house-wings {
position: absolute;
bottom: 0;
height: 125px;
&:before {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: white;
border: 5px solid $color-primary;
box-shadow: inset 0 15px $color-shadow;
}
&:after {
position: absolute;
bottom: 0;
left: 0;
height: 5px;
width: 100%;
background-color: $color-primary;
transform: scaleX(1.2)
}
> .house-roof {
height: 65px;
width: calc(100% + 40px);
left: -20px;
border-bottom: 5px solid $color-primary;
position: absolute;
bottom: 100%;
&:before, &:after {
position: absolute;
height: 100%;
width: 50%;
background-color: $color-roof;
border: 5px solid $color-primary;
border-bottom: none;
}
&:before {
left: 0;
transform-origin: bottom left;
transform: skewX(-30deg);
border-right: none;
}
&:after {
right: 0;
transform-origin: bottom right;
transform: skewX(30deg);
border-left: none;
}
}
.house-ledge {
position: absolute;
bottom: -15px;
width: 100%;
height: 15px;
border: 5px solid $color-primary;
background-color: $color-ledge;
}
}
.house-facade {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
box-shadow: 15px 0 rgba(darken($color-shadow, 20%), 0.2);
&:before, &:after {
position: absolute;
height: 100%;
width: 50%;
background-color: #fff;
top: 0;
border-top: 5px solid $color-primary;
box-shadow: inset 0 calc(var(--front-width) / 6) $color-shadow;
}
&:before {
left: 0;
transform-origin: top left;
transform: skewY(-40deg);
border-left: 5px solid $color-primary;
}
&:after {
right: 0;
transform-origin: top right;
transform: skewY(40deg);
border-right: 5px solid $color-primary;
}
}
$wing-roof-moves: (
6: (
(origin: bottom left, transform: translateY(-10px) rotate(-5deg)),
(origin: bottom right, transform: translateY(-5px) rotate(2deg)),
),
5: (
(origin: bottom right, transform: translateY(-20px) rotate(10deg)),
(origin: bottom left, transform: translateY(-10px) rotate(-2deg)),
),
4: (
(origin: bottom left, transform: translateY(-15px) rotate(-10deg)),
(origin: bottom right, transform: translateY(-10px) rotate(2deg)),
),
3: (
(origin: bottom right, transform: translateY(-20px) rotate(10deg)),
(origin: bottom left, transform: translateY(-10px) rotate(-2deg)),
),
);
$front-roof-moves: (
6: (
(origin: bottom right, transform: translateY(-5px) rotate(5deg)),
(origin: bottom left, transform: translateY(-2px) rotate(-1deg)),
),
5: (
(origin: bottom left, transform: translateY(-10px) rotate(-5deg)),
(origin: bottom right, transform: translateY(-5px) rotate(1deg)),
),
4: (
(origin: bottom right, transform: translateY(-5px) rotate(10deg)),
(origin: bottom left, transform: translateY(-2px) rotate(-2deg)),
),
3: (
(origin: bottom right, transform: translateY(-10px) rotate(-5deg)),
(origin: bottom left, transform: translateY(-5px) rotate(2deg)),
),
);
$house-moves: (
6: (
(transform: scale(.95, 1.05)),
(transform: scale(.98, 1.02)),
),
5: (
(transform: scale(.9, 1.2)),
(transform: scale(.95, 1.05)),
),
4: (
(transform: scale(.9, 1.2)),
(transform: scale(.95, 1.05)),
),
3: (
(transform: scale(.9, 1.2)),
(transform: scale(.95, 1.05)),
),
);
$facade-moves: (
6: (
(transform: scale(.95, 1.05)),
(transform: scale(.98, 1.02)),
),
5: (
(transform: scale(.9, 1.05)),
(transform: scale(.95, 1.02)),
),
4: (
(transform: scale(.9, 1.05)),
(transform: scale(.95, 1.02)),
),
3: (
(transform: scale(.9, 1.05)),
(transform: scale(.95, 1.02)),
),
);
$chimney-moves: (
6: (
(transform: rotate(10deg) translateY(-15px)),
(transform: rotate(-5deg) translateY(-5px)),
),
5: (
(transform: rotate(-10deg) translateY(-15px)),
(transform: rotate(5deg) translateY(-5px)),
),
4: (
(transform: rotate(10deg) translateY(-15px)),
(transform: rotate(-5deg) translateY(-5px)),
),
3: (
(transform: rotate(-10deg) translateY(-15px)),
(transform: rotate(5deg) translateY(-5px)),
),
);
$move-parts: (
wing-roof: $wing-roof-moves,
front-roof: $front-roof-moves,
house: $house-moves,
facade: $facade-moves,
chimney: $chimney-moves,
);
@function either($a, $b) {
@return if($a, $a, $b);
}
@each $part, $move-config in $move-parts {
@each $rooms, $moves in $move-config {
$move-1: nth($moves, 1);
$move-2: nth($moves, 2);
@keyframes #{$part}-#{$rooms}-move {
from {
transform-origin: either(map-get($move-1, origin), bottom center);
}
25% {
transform: map-get($move-1, transform);
}
50% {
transform-origin: either(map-get($move-1, origin), bottom center);
transform: none;
}
51% {
transform-origin: either(map-get($move-2, origin), bottom center);
}
75% {
transform-origin: either(map-get($move-2, origin), bottom center);
transform: map-get($move-2, transform);
}
to {
transform-origin: either(map-get($move-2, origin), bottom center);
transform: none;
}
}
}
}
@for $i from 6 through 3 {
[data-rooms="#{$i}"] {
.house-wings > .house-roof {
animation: wing-roof-#{$i}-move $duration $delay $easing;
}
.house-front > .house-gable {
animation: front-roof-#{$i}-move $duration $delay $easing;
}
.house-wings:before,
.house-left-wing,
.house-right-wing {
animation: house-#{$i}-move $duration $delay $easing;
}
.house-facade,
.house-front .house-window,
.house-doorway {
animation: facade-#{$i}-move $duration $delay $easing;
}
.house-chimney {
animation: chimney-#{$i}-move $duration $delay $easing;
}
}
}
.house-front {
position: absolute;
bottom: 0;
height: 160px;
> .house-window {
width: 60px;
height: 55px;
position: absolute;
left: calc(50% - 30px);
top: -10px;
[data-rooms="4"] &,
[data-rooms="3"] & {
border-bottom-left-radius: 50% 40%;
border-bottom-right-radius: 50% 40%;
&:after {
display: none;
}
}
[data-rooms="4"]:not([data-prev-rooms="3"]) &,
[data-rooms="3"]:not([data-prev-rooms="4"]) &,
[data-rooms="5"]:not([data-prev-rooms="6"]) &,
[data-rooms="6"]:not([data-prev-rooms="5"]) &,
{
> .house-sparkle {
display: block;
}
}
> .house-sparkle {
display: none;
}
}
.house-ledge {
height: 20px;
width: 20px;
position: absolute;
background: #000;
left: calc(50% - 10px);
background-color: $color-ledge;
border: 5px solid $color-primary;
transform: rotate(-45deg) translate(5px, -5px);
&:before, &:after {
position: absolute;
width: calc(var(--front-width) / 1.25);
height: calc(100% + 10px);
top: -5px;
background-color: $color-ledge;
border: 5px solid $color-primary;
}
&:before {
right: 100%;
border-right: none;
}
&:after {
left: 0;
transform-origin: left bottom;
transform: rotate(90deg) translate(-5px, 5px);
border-left: none;
}
}
}
.house-gable {
position: absolute;
bottom: calc(100% - 5px);
left: 0;
width: 100%;
height: 70px;
> .house-roof {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transform: scaleY(0.8);
z-index: 1;
}
}
.house-chimney {
width: 35px;
height: 70px;
position: absolute;
background-color: $color-primary;
left: 15px;
bottom: 100%;
z-index: 0;
}
.house-left-wing,
.house-right-wing {
position: absolute;
height: 100%;
width: calc(50% - var(--front-width) / 2);
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.house-wings {
.house:not([data-rooms="6"]) & {
.house-window:first-child {
display: none;
}
}
.house[data-rooms="3"] & {
.house-window {
display: none;
}
}
.house[data-rooms="6"] &,
.house[data-rooms="5"]:not([data-prev-rooms="4"]) &,
.house[data-rooms="4"][data-prev-rooms="3"] &,
.house[data-rooms="3"] & {
.house-sparkle {
display: block;
}
}
}
.house-left-wing {
left: 0;
}
.house-right-wing {
right: 0;
flex-flow: row-reverse;
}
.house-sparkle {
position: absolute;
height: 90px;
width: 90px;
border-radius: 50%;
border: 5px solid $color-primary;
top: calc(50% - 45px);
left: calc(50% - 45px);
display: none;
// animation-iteration-count: infinite !important;
&:before {
top: 0;
left: 0;
background-color: $color-window-left;
}
&:after {
bottom: 0;
right: 0;
background-color: $color-primary;
}
}
.house-sparkle,
.house-sparkle-dots {
&:before, &:after {
position: absolute;
height: 10px;
width: 10px;
border-radius: 50%;
}
}
.house-sparkle-dots {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
&:before {
bottom: -15px;
right: 40px;
background-color: $color-roof;
}
}
.house[data-rooms="6"] {
.house-left-wing .house-sparkle {
left: calc(25% - 45px);
}
.house-right-wing .house-sparkle {
left: initial;
right: calc(25% - 45px);
}
}
@each $rooms in 6 5 4 3 {
@keyframes sparkle-#{$rooms} {
from {
transform: scale(1);
opacity: 1;
}
to {
transform: scale(2);
opacity: 0;
border-width: 0;
}
}
@keyframes sparkle-dots-#{$rooms} {
from {
transform: scale(1);
}
to {
transform: scale(0);
}
}
.house[data-rooms="#{$rooms}"] {
.house-sparkle {
animation: sparkle-#{$rooms} $duration $easing both;
}
.house-sparkle,
.house-sparkle-dots {
&:before, &:after {
animation: sparkle-dots-#{$rooms} $duration $easing both;
}
}
}
}
@keyframes windows-leave {
to {
width: 0;
}
}
.house-window {
height: 60px;
width: 30px;
border: 5px solid $color-primary;
border-top-left-radius: 30px;
border-top-right-radius: 30px;
background-image: $color-window;
&:before {
height: 100%;
width: 5px;
left: calc(50% - 2.5px);
top: 0;
background-color: $color-primary;
}
&:after {
height: 15px;
width: calc(100% + 20px);
left: -10px;
bottom: 5px;
border-radius: 15px;
background-color: $color-ledge;
border: 5px solid $color-primary;
box-shadow: 0 5px $color-shadow;
}
}
.house-doorway {
width: 65px;
height: 90px;
position: absolute;
bottom: 0;
left: calc(50% - 65px / 2);
}
.house-stairs {
width: 100%;
position: absolute;
bottom: 0;
left: 0;
height: 15px;
border: 5px solid $color-primary;
z-index: 0;
box-shadow: 5px -5px $color-shadow;
&, &:before, &:after {
background-color: white;
}
&:before, &:after {
box-shadow: 5px -5px $color-shadow;
position: absolute;
height: 15px;
width: 100%;
border: 5px solid $color-primary;
}
&:before {
bottom: 100%;
transform: scaleX(.9);
z-index: 0;
}
&:after {
bottom: calc(200% + 5px);
transform: scaleX(.75);
z-index: 0;
}
}
.house-door {
position: absolute;
background-color: $color-primary;
width: 50%;
height: 55px;
left: 25%;
bottom: 35px;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: #EFEFEF;
}
body, html {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
*, *:before, *:after {
box-sizing: border-box;
position: relative; // don't @ me
}
*:before, *:after {
content: '';
display: block;
}
// Styling input ranges is painful
// Styling Cross-Browser Compatible Range Inputs with Sass
// Github: https://github.com/darlanrod/input-range-sass
// Author: Darlan Rod https://github.com/darlanrod
// Version 1.4.1
// MIT License
$track-color: linear-gradient(to bottom, $color-ledge, $color-ledge 49.9%, darken($color-ledge, 5%) 50%, darken($color-ledge, 5%) 100%) !default;
$thumb-color: $color-primary !default;
$thumb-radius: 20px !default;
$thumb-height: 40px !default;
$thumb-width: 40px !default;
$track-width: 330px !default;
$track-height: 25px !default;
$track-shadow-color: rgba(0, 0, 0, .2) !default;
$track-border-width: 5px !default;
$track-border-color: $color-primary !default;
$track-radius: 25px !default;
@mixin track {
cursor: pointer;
height: $track-height;
transition: all .2s ease;
width: $track-width;
}
@mixin thumb {
background: $thumb-color;
border-radius: $thumb-radius;
cursor: pointer;
height: $thumb-height;
width: $thumb-width;
}
[type='range'] {
-webkit-appearance: none;
margin: $thumb-height / 2 0;
width: $track-width;
&:focus {
outline: 0;
&::-webkit-slider-runnable-track {
background: $track-color;
}
&::-ms-fill-lower {
background: $track-color;
}
&::-ms-fill-upper {
background: $track-color;
}
}
&::-webkit-slider-runnable-track {
@include track;
background: $track-color;
border: $track-border-width solid $track-border-color;
border-radius: $track-radius;
}
&::-webkit-slider-thumb {
@include thumb;
-webkit-appearance: none;
margin-top: ((-$track-border-width * 2 + $track-height) / 2) - ($thumb-height / 2);
}
&::-moz-range-track {
@include track;
background: $track-color;
border: $track-border-width solid $track-border-color;
border-radius: $track-radius;
}
&::-moz-range-thumb {
@include thumb;
}
&::-ms-track {
@include track;
background: transparent;
border-color: transparent;
border-width: ($thumb-height / 2) 0;
color: transparent;
}
&::-ms-fill-lower {
background: $track-color;
border: $track-border-width solid $track-border-color;
border-radius: $track-radius * 2;
}
&::-ms-fill-upper {
background: $track-color;
border: $track-border-width solid $track-border-color;
border-radius: $track-radius * 2;
}
&::-ms-thumb {
@include thumb;
margin-top: 0;
}
}
View Compiled
const house = document.querySelector('#house');
const range = document.querySelector('#range');
const label = document.querySelector('#label');
const f = new Flipping();
const update = f.wrap(rooms => {
const prevRooms = house.getAttribute('data-rooms');
house.setAttribute('data-prev-rooms', prevRooms);
house.setAttribute('data-rooms', rooms);
label.setAttribute('data-prev-rooms', prevRooms);
label.setAttribute('data-rooms', rooms);
label.setAttribute('data-rooms-delta', rooms - prevRooms);
});
const range$ = Rx.Observable
.fromEvent(range, 'input')
.map(e => e.target.value)
.startWith(6);
range$.subscribe(update);
View Compiled
This Pen doesn't use any external CSS resources.